# Haskell: sequenceA (explanation)

Context:

http://learnyouahaskell.com/functors-applicative-functors-and-monoids#applicative-functors

ctrl+f “Let’s give our function a whirl on some applicatives.”

A colleague was overcomplicating it a bit.

There isn’t really a need to manually evaluate sequenceA [(+1)] , and see what it does exactly “under the hood”.

The article does not bother to do that, and doing so kinda defeats the purpose of having the sequenceA abstraction in the first place: to reduce cognitive load.

(The article used a simpler example: sequenceA [Just 3, Just 2, Just 1] == Just [3,2,1] to illustrate the abstraction. Once you see the abstract pattern, there is no need to go “under the hood” for other applicative types.)

All that’s required to understand the behaviour of sequenceA [(+1)], is to see that:

- the outer [] is a Foldable . In this case, this just means it’s a suitable container that can be used with sequenceA .
- the inner (+1) is an Applicative . In this case, this means one can lift []’s constructor (i.e. (:)) into the (+1) .
- sequenceA’s job is to deconstruct the outer container [], and reconstruct it inside the Applicative.

Then, knowing that (+1) == \r -> r + 1 , and reading the earlier part of the same article explaining how lifting works with this particular Applicative, it becomes clear that:

sequenceA [(+1)]== sequenceA [(\r -> r + 1)]== (\r -> [r+1]) -- deconstruct outer [] , and reconstruct it inside the applicative

Similarly,

sequenceA [(+1),(+2)]== sequenceA [(\r -> r + 1), (\r -> r + 2)]== (\r -> [r + 1, r + 2])

Abstractly,

-- | deconstruct outer Foldable t, and reconstruct it inside

-- | Applicative fsequenceA :: (Foldable t, Applicative f) => t (f a) -> f (t a)sequenceA ( _ :: t (f a) ) = _ :: f (t a)

— -

It gets even easier with do notation:

sequenceA [ (+1), (+2) ]-- is equivalent todo x <- (+1) -- after deconstructing [] y <- (+2) -- after deconstructing [] pure [x, y] -- reconstructing it inside the applicative

-- (pure wraps it back into the applicative)

What? CHARMANDER is evolving!

do

x <- (+1)

y <- (+2)

pure $ x:y:[]-- charmeleon

What? CHARMELEON is evolving!

{-# LANGUAGE ApplicativeDo #-}

{-# LANGUAGE ScopedTypeVariables #-}sequenceA' :: forall t f a . (Foldable t, Applicative f) =>

t (f a) -> f [a]

sequenceA' xs = foldr g (pure []) xs -- foldr deconstructs

where

g x r = do

x' <- (x :: f a)

r' <- (r :: f [a])

pure $ x':r' -- reconstruct-- charizard

— -

Bonus: sample code

dataLista = Cons a (Lista) | Nil' derivingShowinstanceFoldableListwhere

foldr _ z Nil' = z

foldr f z (Cons x xs) = x `f` foldr f z xsseqA' :: (Foldablet,Applicativef) => t (f a) -> f (Lista)

seqA' xs = foldr (\x r -> Cons <$> x <*> r) (pure Nil') xs

Try in GHCi:

Prelude> seqA' (Cons (Just 1) Nil')

Just (Cons 1 Nil')Prelude> seqA' [Just 1] -- WARNING: non-standard usage! (for curiosity)

Just (Cons 1 Nil') -- deconstruct [], but reconstruct with List-- WARNING: second example is not normally possible