Programming with Effects
matfournier.com
matfournier.com
As someone who is interested in FP, but still at the beginning of the journey, I found the blog post interesting to read, especially intuition for every Monad.
For example, I hace a monad that saves to a database using effects. I change the effect to update an array instead and I have code that I can use in a unit test.
A more interesting example could be monads as used in Haxl, which give an alternative monad in which to run database queries, which can perform complicated batching of requests behind the scenes with no change of business logic code.
I had a colleague who wanted to rewrite the same piece of code using Observables instead.
Later in a different company I met someone who was working on the exact opposite, i.e. taking Observable code and rewriting it as Futures because "observables are confusing".
Just extract these things behind an interface and call it a day.
Anytime you want to test (and e.g. don't perform the actual side effects but mock them)?
Or change from e.g. logging to a file to logging to a DB or syslog?
And lots of other cases!
Effects are different because side effects are impure which is not allowed by default in a pure language. Machinery is needed to hide the effects in effect-managing containers so they don't contaminate pure code.
So, you might have a piece of code which can fail at using some User properties to compute a score of some sort
computeScore :: MonadError Error m => User -> m Score
and also a piece of code that pulls a given user from a database getUser :: MonadDatabase m => UserID -> m User
and we can compose them getAndComputeScore :: (MonadError Error m, MonadDatabase m) => UserID -> m Score
getAndComputeScore id = do
user <- getUser
computeScore user
In some sense, each of these three functions operates in a different (abstract) effect stack and the calls to getUser and computeScore were transparently "upgraded" to a more comprehensive effect stack when they were called in getAndComputeScore.This is the basis for "effect tracking" where each piece of code is written to the minimal, necessary effect specification. Their ability to compose and operate within other compatible (abstract) effect stacks is used regularly to compose small programs into bigger ones. Then, finally, you just make a big type
data ConcreteEffects a = ConcreteEffects ...
instance MonadError Error ConcreteEffects where ...
instance MonadDatabase ConcreteEffects where ...
which instantiates all of your abstract effects concretely. You might even make two, one for testing data ConcreteTestEffects a = ConcreteTestEffects ...
instance MonadError Error ConcreteTestEffects where ...
instance MonadDatabase ConcreteTestEffects where ...
These will look like compositions of the basic effects from this article. For instance, if you imagine a type of DatabaseHandles, you might have data ConcreteEffects a = ConcreteEffects (DatabaseHandle -> Either Error a)
which you can stare at and recognize to be Either and Reader combined together.The word "effects" has a long and storied history in programming language theory that predates algebraic effects/handlers by decades. The study of effect systems includes algebraic effects but also monads and other type and effect systems. In some situations the lines between these are blurred, for example with "extensible effects" which are algebraic effects implemented by a free(r) monad combined with "data types a la carte"-style open unions.
The simplest example is the continuation effect. It's not immediately clear why this effect isn't algebraic (it's not even immediately clear what "algebraic" means) but suffice to say continuations are very weird and behave very differently from other effects.
At the same time, they're very useful and are a useful part of someone's programming vocabulary.
Because a news site is only for "typical" things?