How does sequenceA work on lists of pairs?
It uses mappend
. The Applicative
instance it uses looks like this:
instance Monoid a => Applicative ((,) a) where
pure x = (mempty, x)
(af, f) <*> (ax, x) = (mappend af ax, f x)
In Haskell, typeclass instances for a type can be "conditional" on the existence of other typeclass instances for parts of the type. Not all type constructors
of the form ((,) a)
are instances of Applicative
, but only those for which the a
type has a Monoid
instance.
These required constraints appear before the =>
in the instance's Haddocks, like this:
Monoid a => Applicative ((,) a)
Why is the Monoid
instance required? For one, pure
for ((,) a)
needs to materialize an a
value out of thin air to put in the first element of the tuple. mempty
for the type a
does the job.
There can be chains of required constraints that are several levels deep. For example, why does the following work?
ghci> import Datta.Function ((&)) -- flipped application
ghci> [(id :: String -> String, 2 :: Int), (\x -> x ++ x, 1)] & sequenceA & fst $ "foo"
"foofoofoo"
Here the first component is a function. As before, it must have a Monoid
instance for the sequenceA
to work. But when is the type a -> b
a Monoid
? Looking at the Haddocks, we find:
Monoid b => Monoid (a -> b)
That is, functions are Monoid
s when the return type (here String
) is a Monoid
.
Actually, there's another Monoid
instance for functions available through the Endo
newtype. It's common to use newtypes to select which instance to use for a given operation, although it requires some amount of wrapping and unwrapping.