Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
26 views

Impact of Non Functional Programming

What is functional programming? In order to unveil what defines functional programming let’s start with things it is definitely not: Functional programming is not a language. There’s a common misconception that there are “functional programming languages” like Elixir, Haskell, and Scala and that functional programming concepts are only useful in those languages. Whilst it’s true that these languages do encourage writing functional programs (and in some cases, enforce the ru

Uploaded by

Abhinav Agrawal
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
26 views

Impact of Non Functional Programming

What is functional programming? In order to unveil what defines functional programming let’s start with things it is definitely not: Functional programming is not a language. There’s a common misconception that there are “functional programming languages” like Elixir, Haskell, and Scala and that functional programming concepts are only useful in those languages. Whilst it’s true that these languages do encourage writing functional programs (and in some cases, enforce the ru

Uploaded by

Abhinav Agrawal
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 3

What is functional programming?

In order to unveil what defines functional programming let’s start with things it
is definitely not:

Functional programming is not a language. There’s a common misconception that there


are “functional programming languages” like Elixir, Haskell, and Scala and that
functional programming concepts are only useful in those languages. Whilst it’s
true that these languages do encourage writing functional programs (and in some
cases, enforce the rules), functional programming is not unique to them and the
practices are useful whether you’re writing ML or PHP.
Functional programming is not a library. This is a twist on the last point, with
libraries like Vavr for Java and ReactiveX for JavaScript claiming to be one-stop
shops for functional programming, it’s easy to think that the principles might not
apply if you’re not using them or can’t use them.
Functional programming is not just for academics. Although the roots of functional
programming are deep-seated in mathematics, the principles can be applied by any
engineer and improve the quality and predictability of that engineer’s code.
Just to clarify, any of these things are bad — if you can write Haskell, or use
Vavr in your Java projects, or have a background in mathematics, that’s a great
thing — but that they are not necessary to apply the principles of functional
programming in your day-to-day code. Yes, even if your employer insists on using
Java 5, PHP 5, or Perl 5. Why is it always version 5?

With this in mind, what is functional programming? Let’s break it down into its
core principles:

Side Effects & Pure Functions


To understand functional programming first, we need to understand side effects. A
side effect is when a function relies on, or modifies, something outside its
parameters to do something. For example, a function which reads or writes from a
variable outside its own arguments, a database, a file, or the console can be
described as having side effects.

A function is pure if, given the same inputs, it a) always returns the same output
and b) does not have any side effects. At first, it may not be apparent why pure
functions are preferable, but take a look at this example (written in Perl, which
is about the furthest thing from a “functional programming language” that I can
imagine):

https://gist.github.com/m-doughty/1a22ce833f707303d84c4c630044c425

The ‘triple’ function is much easier to unit test, because its result depends
solely on its input. It’s also much easier to run in parallel because it doesn’t
rely on access to shared state. Most importantly, it’s predictable: triple(5) will
always return 15, regardless of how many times we run it or what the state of the
surrounding system is saying.

But In The Real World, We Need IO


An application isn’t really useful if it can’t interact with the outside world,
though, is it? So how do we handle side effects like printing to the console,
reading & writing from databases, generating random numbers, etc? The answer is
that we write our business logic as pure functions, and move side effects to the
edges of our process — that is, instead of reading from our database in the middle
of our process; we do IO, then we have a core of business logic, then we do IO
again.

In the Java world, this is already considered best practice. Alistair Cockburn
explains in his introduction to the Hexagonal Architecture that business logic
should not deal with IO, and these should be kept at the edges of the software and
implemented with interfaces to make them easier to test. Uncle Bob Martin’s Clean
Architecture is, in its essence, a guide to keeping side effects at the edges of
your system designs.

So, the goal of a functional programmer shouldn’t be to eliminate IO, but to move
it to the edges in order to keep our business logic pure, composable, and testable.

Referential Transparency & Data Transformations


‘Referential transparency’ is a fancy way of saying that you can replace the
function with its result, and vice versa, without incurring side effects. (2 + 2) *
4 === 4 * 4.

From the simplest calculator to the most complex data science model, the purpose of
programming is to take an input or inputs (whether that comes from a user, a
sensor, another application, or anywhere else) and transform it into an output. By
thinking about programming this way — “I have this input and I want this output” — 
we can break our code down into functions, plumbed together into pipes, which take
our input data and apply the requisite transformations to turn them into output
data. That plumbing relies on referential transparency.

Immutable State
Once the preserve of niche academic languages, immutable values have now made their
way into most mainstream languages. Whether it’s const in ES6, the final keyword in
Java or val/var in Kotlin, most languages have embraced a future wherein we don’t
modify data structures, but copy them.

This might seem counter-intuitive: why would we want to copy something instead of
changing it? The answer lies in unintended effects:

https://gist.github.com/m-doughty/ee1ec19e7ba313ed886de93d4c4db9cf

This might seem like a contrived example — everyone knows that object assignment
duplicates the reference, right? In complex code, though, it’s actually quite a
common issue. A reference will be duplicated somewhere in the code, then passed
into another function that doesn’t realize it’s working on a shared reference, and
then it’ll update the state of an object being used elsewhere in the system.
Immutable data structures allow us to avoid this possibility entirely.

Haskell actually goes a step further and doesn’t allow values to be reassigned. If
you say x is 3, then x is 3 for the remainder of the lexical scope and there’s no
way to tell the program otherwise.

Recursion
In imperative and object-oriented programming, it’s common to use loops (for,
while, forEach) which have side effects (increasing the iterator, changing the
‘while’ variable, or modifying the structure that’s being iterated over). In
functional programming, we prefer recursion. A recursive function is a function
which calls back to itself with modified input values (otherwise we’d have an
infinite loop, which is predictable but not very useful), until it ‘finishes’
processing.

The most common recursive functions to replace loops (all of which are already
implemented in most languages) are:

map, which takes an input collection and applies a function to each element in the
collection, then returns an output collection of equal size (note: the input
collection is immutable, so it will not be changed in the process);
filter, which takes an input collection and a predicate (a function which returns a
boolean), and tests every input against the predicate, then returns only a
collection of the elements which return true; and
reduce (or fold), which takes an input collection and applies a function which
takes an accumulator and a value and turns it into a single value, eventually
returning a single value (like a String or an Int).
All of these recursive functions are examples of higher-order functions, meaning
that they are functions which take functions as parameters. This is commonplace in
functional programming because it allows us to write highly reusable code and
compose terse data pipelines far more easily.

Functors, which are context wrappers which define how functions can be applied to
their boxed values;
Applications, which are context wrappers which define how boxed functions can be
applied to their boxed values; and
Monads, which are context wrappers which define how a function which returns a
boxed value can be applied to their boxed values.
Maybe, in Haskell, is an example of all three. It defines how functions can be
applied to its value, how boxed functions can be applied to its value, and how
functions which return boxed values can be applied to its value. I really recommend
reading Bhargava’s piece on the subject, as the diagrams make this a lot more
digestible, but if you’ve worked with Options, Futures, Eithers, or anything
similar which wraps a value, chances are you’re already using context day-to-day
(or you’re a banker, in which case, these terms have very different meanings).

You might also like