
Briefly on the Purpose of Functors, Applicatives and Monads - Tehnix
https://codetalk.io/posts/2015-11-28-briefly-on-the-purpose-of-functors-applicatives-and-monads.html
======
happy4crazy
I like to think of a functor/applicative/monad f a as being "more or less" an
a.

For example, take a list of Strings. It's "more or less" a single string, it
just hasn't made up its mind yet :) When you say fmap reverse myStrings,
you're saying: yeah yeah, I know my string hasn't made up its mind yet, but
just reverse it. So you reverse all the possibilities. When you say

    
    
      (++) <$> myStrings <*> yourStrings
    

you're saying: yeah yeah, I know my string hasn't made up its mind yet, and
neither has your string, but just concatenate them. So you concatenate all the
pairwise possibilities. The monad stuff says you can do control flow: (yeah
yeah), but if my string is this long, and your string is a palindrome...

Promises: A Promise Int isn't an Int, but eh, it's more or less an Int. Just
as you can add 1 to a regular Int, you can fmap (+1) promisedInt. Just as you
can replicate 3 'a' to get "aaa", you can

    
    
      replicate <$> promisedInt <*> promisedChar
    

to promise some repetitive String. (And presumably promisedInt and
promisedChar will resolve themselves in parallel!) The monad stuff: if this
promised Int ends up being prime, then...

Parsers: A Parser Int (something that can gobble up a string and produce an
Int) isn't an Int, but (in some contexts, if it's helpful) you can think of it
as being more or less an Int. Saying fmap (+1) intParser says make a parser
that parses whatever intParser does, and then adds 1 to the result. Doing

    
    
      replicate <$> intParser <*> charParser
    

makes a parser that tries to parse an Int, and then a Char, and then gives you
a repetitive String. Monad stuff: if I parse a prime number, then...

Functions that take some fixed argument type, say Float. A Float -> String
isn't a String, obviously, but it's more or less a String :) It's just missing
a Float. If I say fmap reverse justNeedAFloatToBeAString, I'm making a new
function will take a float and then reverse whatever you get by feeding it to
justNeedAFloatToBeAString. If I

    
    
      (++) <$> almostAString <*> almostAnotherString,
    

I'm making a new function of type Float -> String that feeds a Float (the same
Float) to both subcomputations and then concatenates their results. Monad
stuff: if this almost-Int ends up being prime...

Functor says you can treat a single f a as more or less a single regular a.
Applicative says you can treat any number of f a values as more or less any
number of regular a values. Monad says you can do control flow with f a values
as if they were regular a values.

