Haskell has Functor
, Applicative
and Monad
instances defined for functions (specifically the partially applied type (->) a
) in the standard library, built around function composition.
Understanding these instances is a nice mind-bender exercise, but my question here is about the practical uses of these instances. I'd be happy to hear about realistic scenarios where folks used these for some practical code.
Functors apply a function to a wrapped value: Applicatives apply a wrapped function to a wrapped value: Monads apply a function that returns a wrapped value to a wrapped value. Monads have a function >>= (pronounced "bind") to do this.
Functor is also important in its role as a superclass of Applicative and of Traversable . When working with these more powerful abstractions, it's often very useful to reach for the fmap method. Show activity on this post. For example, it's possible to derive the function lift in a way that works for any functor.
A functor takes a pure function (and a functorial value) whereas a monad takes a Kleisli arrow, i.e. a function that returns a monad (and a monadic value). Hence you can chain two monads and the second monad can depend on the result of the previous one.
One of the simplest, and easiest to understand, functors is Maybe. It's also sometimes known as the Maybe monad, but this is not a monad tutorial; it's a functor tutorial. Maybe is many things; one of them is a functor. In F#, Maybe is called option .
A common pattern that involves Functor and Applicative instances of functions is for example (+) <$> (*2) <*> (subtract 1)
. This is particularly useful when you have to feed a series of function with a single value. In this case the above is equivalent to \x -> (x * 2) + (x - 1)
. While this is very close to LiftA2
you may extend this pattern indefinitely. If you have an f function to take 5 parameters like a -> a -> a -> a -> a -> b
you may do like f <$> (+2) <*> (*2) <*> (+1) <*> (subtract 3) <*> (/2)
and feed it with a single value. Just like in below case ;
Prelude> (,,,,) <$> (+2) <*> (*2) <*> (+1) <*> (subtract 3) <*> (/2) $ 10
(12.0,20.0,11.0,7.0,5.0)
Edit: Credit for a re-comment of @Will Ness for a comment of mine under another topic, here comes a beautiful usage of applicative over functions;
Prelude> let isAscending = and . (zipWith (<=) <*> drop 1)
Prelude> isAscending [1,2,3,4]
True
Prelude> isAscending [1,2,5,4]
False
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With