Earlier, it used to have map and sequence with following implementation:
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
sequence :: Monad m => [m a] -> m [a]
then haskell contributors did generalize to:
traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
sequenceA :: (Applicative f, Traversable t) => t (f a) -> f (t a)
Why they choose applicative over monad?
How they become the idea to generalize mapM and sequence? I want to understand the process, when I have to be more abstract. As you can see, functions mapM and sequence work only on list, but traverse and sequenceA are more abstract and work with all datatype that has Traversable implemented.
Applicative chosen because we want to chain actions but action order does not depend on previous results.
Monad: action1 >>= \resultOfAction1 -> if P(resultOfAction1) then action1 else action2 (action chain may vary depending on results)
Applicative: processCombinedResult <$> action1 <*> action2 <*> action3 (action chain fixed)
When traversing Traversable action order dictated by Traversable's internal structure and does not depend on each other results. Monad also can be used, but it more restrictive and it's ability to chain actions "dynamically" depending on results of previous actions is not required to implement these functions. So Applicative is chosen as less restrictive class which provides required functionality.
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