This post is part of a series called functional fundamentals. See theintroduction and index. That's also where you can request specific topics
Note that I am not an authoritative figure on these subjects, if you see something you think might be incorrect or incomplete, please point it out with a comment, let's prevent mistakes from spreading :-)
By this point in the series you should already know a lot about the advantages of (pure) functional programming:
- Safe composition (easy refactoring, guaranteed integration,real monads...)
- Strong type systems (no run-time errors, nobackdoors)
- Explicit data-dependencies (good for various optimizations)
And now it's time to talk about the catch.
Functional code doesn't do anything. It's just a value. EvenreadLn "Hello, World!"
(theprint("Hello, World!")
equivalent in Haskell) is just avalue of typeIO ()
.
The program needs to be evaluated, it needs to be applied to inputs at the very least. It needs to interact with the world, which unfortunately, is not functional, at least not in a way that is useful to us.
In places where this happens, we have a functional program boundary, where the functional world ends and the imperative one begins. Haskell crosses this boundary usingdo
blocks(EDIT: this is not entirely accurate, see comments), Elm has The Elm Architecture which is specific to websites.
On the boundaries, run-time exceptions become possible, composition is non-trivial and the type system is often more generic.
The larger the boundaries, the less use you will have out of functional programming.
Boundaries can be shifted however. Functional programming only cares about data transformations, not so muchwhere orwhen they happen.
Big data applications have leveraged this by extending the boundary over a network of computers rather than single ones. AWS lambda and Google Functions are using a similar concept, treating imperative programs as pure functions. In fact, mapping a pure function over an array, list or dict isembarrassingly parallel.
Elm, using TEA, instead hides the imperative world by segmenting the problem into functional parts, abstracting away the imperative glue into commands and messages. This way the programmer is only bothered with the functional stuff.
In short: how a functional language, library or framework represents a problem can greatly affect how large your functional boundaries are, smaller boundaries generally being better.
Further reading:
Top comments(3)

the boundary in haskell ismain
, notdo
, although that has as much to do with laziness as fp.

I wasn't as accurate as I should have been in my post.
You're right in thatmain
crosses the borderof your program.do
blocks are just syntactic sugar for effectfull monads.
However, if you're using monads as effects you are essentially doing imperative programming. A single, isolated, effectfull monad, such asMaybe
used as the result division by 0, I would not consider imperative yet, but largedo
blocks full of them I would definitely consider part of thefunctional border.
Some comments may only be visible to logged-in visitors.Sign in to view all comments.
For further actions, you may consider blocking this person and/orreporting abuse