From the Typeclassopedia:
sequence :: Monad m => [m a] -> m [a]
Takes a list of computations and combines them into one computation which collects a list of their results. It is again something of a historical accident that sequence has a Monad constraint, since it can actually be implemented only in terms of Applicative.
And indeed, there is sequenceA which operates on Applicative types.
sequenceA :: (Applicative f, Traversable t) => t (f a) -> f (t a)
But wait, why does sequenceA need the Traversable constraint when it can be implemented without it?
seqA :: Applicative f => [f a] -> f [a]
seqA = foldr fx (pure [])
where
fx f fs = pure (:) <*> f <*> fs)
This is a subject that can be initially confusing because there is a lot of history and change around it, and older explanations are out of date. The history is roughly this:
The idea of the sequence operation dates back to the 1990s, when the Monad class was incorporated into Haskell and people first formulated generic operations for it. The signature that you quote from the Typeclassopedia reflects this: sequence :: Monad m => [m a] -> m [a]. It can work with any monad, but it is hardcoded to work on lists.
The Applicative class was developed during the mid-to-late 2000s; the seminal paper that everybody cites is McBride and Patterson (2008), "Applicative Programming with Effects". McBride and Patterson also note that:
The old monadic sequence operation can in fact be generalized to dist :: Applicative f => [f a] -> f [a]. The Monad constraint is too narrow!
Likewise, the old mapM function (close relative to sequence) generalizes to traverse :: Applicative f => (a -> f b) -> [a] -> f [b].
This can be generalized to non-list data structures by putting these operations into a Traversable class that they propose in the paper.
The Applicative and Traversable classes were added into the GHC base libraries, with some small changes. The dist function was named sequenceA instead, and the Foldable class joined Traversable for types that support only a subset of Traversable's requirements.
These classes proved extremely popular. But that shows that the original sequence :: Monad m => [m a] -> m [a] signature was wrong in hindsight.
So finally, fast-forward to 2015, when GHC implemented the Applicative/Monad Proposal (make Applicative a superclass of Monad) and the Foldable/Traversable Proposal, where the base libraries were revised in order to get them close to the ideal, hindsight-informed design.
The Foldable/Traversable Proposal, however, did not change the signature of sequence. I can't tell you precisely why, but the answer is going to be some obtuse detail that boils down to historical reasons, backward compatibility or something like that. But I can tell you that if we could start all over again:
sequence would have sequenceA's signature;
sequenceA would not exist independently of sequence;
mapM is just traverse with the wrong signature, and thus would not exist independently either.
Related
I am trying to implement MonadUnliftIO for Snap and analyzing Snap classes.
I discovered that ap is used for implementing Applicative while ap requires Monad and Monad requires Applicative. It looks like a loop.
I thought till now that is not possible to write such things.
What is the limit for such kind of trick?
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
class Applicative m => Monad m where
return :: a -> m a
instance Applicative Snap where
pure x = ...
(<*>) = ap
ap :: Monad m => m (a -> b) -> m a -> m b
This only works because Snap has a Monad instance (and it's actually in scope at that point).
Effectively, the compiler handles declarations in two separate passes: first it resolves all the instance heads
instance Applicative Snap
instance Monad Snap
...without even looking in the actual method implementations. This works out fine: Monad is happy as long as it sees the Applicative instance.
So then it already knows that Snap is a monad. Then it proceeds to typecheck the (<*>) implementation, notices that it requires the Monad instance, and... yeah, it's there, so that too is fine.
The actual reason we have ap :: Monad m => ... is mostly historical: the Haskell98 Monad class did not have Applicative or even Functor as a superclass, so it was possible to write code Monad m => ... that could then not use fmap or <*>. Therefore the liftM and ap functions were introduced as replacement.
Then, when the better current class hierarchy was established, many instances were simply defined by referring back to the already existing Monad instance, which is after all sufficient for everything.
IMO it is usually a good idea to directly implement <*> and definitely fmap before writing the Monad instance, rather than the other way around.
I think you are imagining a cycle like this:
(<*>) is implemented with ap
(>>=) is implemented with (<*>)
ap is implemented using (>>=)
And yes, if you try this, it will indeed give you an infinite loop!
However, this is not what your code block does. Its implementations look more like this:
(>>=) is implemented from first principles, without using any Applicative functions
ap is implemented using (>>=)
(<*>) is implemented in terms of ap
Which is obviously fine — there’s no cycles of any sort in this set of function definitions.
One thing which might still be a bit confusing is: how can you implement an Applicative function in terms of a Monad function, when a type can only be a Monad if it is already Applicative? To answer this, let’s add explicit type signatures to your code sample (note this requires language extensions to compile):
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
class Applicative m => Monad m where
return :: a -> m a
instance Applicative Snap where
pure :: a -> Snap a
pure x = ...
(<*>) :: Snap (a -> b) -> Snap a -> Snap b
(<*>) = ap
ap :: Monad m => m (a -> b) -> m a -> m b
The answer is now clear: we are not in fact defining (<*>) for just any arbitrary Applicative type! Rather, we are defining it for Snap only, which means we can use any function defined to work on Snaps — including those from the Monad typeclass. The fact that this function happens to be within an instance Applicative Snap block doesn’t matter: in all other respects, it’s just an ordinary function definition, and there’s no reason why the full range of Snap functions shouldn’t be able to appear in it.
There should be some instance Monad Snap somewhere else. The ap use in the Applicative instance will make use of >>= from that instance.
In general, an instance for Applicative can not make use of ap in this way, but when then applicative is also a monad, I think it is quite common to do so, since it's convenient.
Note that, if one chooses this route, it should avoid using <*> or ap inside the definition of >>=, since that could lead to infinite recursion.
The fact that the two instances are mutually recursive, in some sense, is not an issue. Haskell allows mutual recursion, and this also reflects on instances. The programmer however must ensure that the recursion actually terminates, or be prepared to have a non-terminating program.
Why are we calling a flip of structure a "sequence" and why are we talking about "traverse" and "Traversal" ?
I'm adding the implementation in haskell of these concepts as a matter to discussion...
class (Functor t, Foldable t) => Traversable t where
{-# MINIMAL traverse | sequenceA #-}
-- | Map each element of a structure to an action, evaluate these actions
-- from left to right, and collect the results. For a version that ignores
-- the results see 'Data.Foldable.traverse_'.
traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
traverse f = sequenceA . fmap f
-- | Evaluate each action in the structure from left to right, and
-- and collect the results. For a version that ignores the results
-- see 'Data.Foldable.sequenceA_'.
sequenceA :: Applicative f => t (f a) -> f (t a)
sequenceA = traverse id
Let's begin by considering fmap:
fmap :: Functor t => (a -> b) -> t a -> t b
We can describe what it does as finding all a values in a t a and applying a function to them. Note that, infinite structure shenanigans aside, the order in which the implementation of fmap reaches the a values to modify them doesn't matter as far as the final result is concerned.
Now let's have a look at traverse:
traverse :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)
Like fmap, traverse also involves applying a function to values found in a structure (it's no wonder traverse's forerunner was called mapM). traverse, however, also produces applicative effects for each of the a values (the f in a -> f b), and it involves combining those effects in some order to get the overall f (t b) result. In general (i.e. as long as f isn't a commutative applicative, such as Maybe), the order of effects affects the result. That being so, any Traversable instance corresponds to a specific order in which the values in the structure will be visited. The name "traverse" (that is, as Will Ness points out, "travel across or through") is meant to convey this sense of direction.
On a related note, traverse can be decomposed into a plain mapping which produces effects followed by the sequencing of those effects...
sequenceA :: (Applicative f, Traversable t) => t (f a) -> f (t a)
traverse f = sequenceA . fmap f
sequenceA = traverse id
... ergo the "sequence" name.
It is also worth emphasising that traverse does capture various ways of going through a structure and doing things at each stop (cf. for being the name for flip traverse). In particular, we recover fmap by picking Identity as the Applicative functor (i.e. by not actually generating any effects), and foldMap (that is, list-like folding) by picking Monoid m => Const m instead. Things we can't do with traverse include dropping, duplicating or rearranging elements -- it doesn't allow tearing down a data structure in arbitrary ways like a general fold/catamorphism does. With traverse, we can move through a Traversable structure, but we can't reshape it.
It's "to sequence", not "a". I.e. "Arrange in a particular order", here from left to right. And it is a generalization of sequence :: Monad m => [m a] -> m [a] (note the old base version), which may make the name more obvious.
What does sequenceA from Traversable stand for? Why is there capital A at the end? I've been learning Haskell for a few months now and this is one of those things that's been bugging me for a while.
The "A" stands for Applicative, as in the constraint in sequenceA's type:
sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)
That the "A" is there is fruit of a historical accident. Once upon a time, neither Applicative nor Traversable existed in Haskell. Nonetheless, a function exactly like sequenceA already existed -- except that it had a much more specific type:
sequence :: Monad m => [m a] -> m [a]
When Applicative and Traversable were introduced, the function was generalised from lists to any Traversable [1]:
sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)
sequence's Monad constraint is unnecessarily restrictive. Back then, however, generalising it further to Applicative was not an option. The problem was that until early last year Applicative was not a superclass of Monad as it is supposed to be, and therefore generalising the signature to Applicative would break any use of sequence with monads that lacked an Applicative instance. That being so, an extra "A" was added to the name of the general version.
[1]: Note, however, that the Prelude continued to carry the list-specific version until quite recently.
I have become rather interested in how computation is modeled in Haskell. Several resources have described monads as "composable computation" and arrows as "abstract views of computation". I've never seen monoids, functors or applicative functors described in this way. It seems that they lack the necessary structure.
I find that idea interesting and wonder if there are any other constructs that do something similar. If so, what are some resources that I can use to acquaint myself with them? Are there any packages on Hackage that might come in handy?
Note: This question is similar to
Monads vs. Arrows and https://stackoverflow.com/questions/2395715/resources-for-learning-monads-functors-monoids-arrows-etc, but I am looking for constructs beyond funtors, applicative functors, monads, and arrows.
Edit: I concede that applicative functors should be considered "computational constructs", but I'm really looking for something I haven't come across yet. This includes applicative functors, monads and arrows.
Arrows are generalized by Categories, and so by the Category typeclass.
class Category f where
(.) :: f a b -> f b c -> f a c
id :: f a a
The Arrow typeclass definition has Category as a superclass. Categories (in the haskell sense) generalize functions (you can compose them but not apply them) and so are definitely a "model of computation". Arrow provides a Category with additional structure for working with tuples. So, while Category mirrors something about Haskell's function space, Arrow extends that to something about product types.
Every Monad gives rise to something called a "Kleisli Category" and this construction gives you instances of ArrowApply. You can build a Monad out of any ArrowApply such that going full circle doesn't change your behavior, so in some deep sense Monad and ArrowApply are the same thing.
newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }
instance Monad m => Category (Kleisli m) where
id = Kleisli return
(Kleisli f) . (Kleisli g) = Kleisli (\b -> g b >>= f)
instance Monad m => Arrow (Kleisli m) where
arr f = Kleisli (return . f)
first (Kleisli f) = Kleisli (\ ~(b,d) -> f b >>= \c -> return (c,d))
second (Kleisli f) = Kleisli (\ ~(d,b) -> f b >>= \c -> return (d,c))
Actually every Arrow gives rise to an Applicative (universally quantified to get the kinds right) in addition to the Category superclass, and I believe the combination of the appropriate Category and Applicative is enough to reconstruct your Arrow.
So, these structures are deeply connected.
Warning: wishy-washy commentary ahead. One central difference between the Functor/Applicative/Monad way of thinking and the Category/Arrow way of thinking is that while Functor and its ilk are generalizations at the level of object (types in Haskell), Category/Arrow are generelazation of the notion of morphism (functions in Haskell). My belief is that thinking at the level of generalized morphism involves a higher level of abstraction than thinking at the level of generalized objects. Sometimes that is a good thing, other times it is not. On the other-hand, despite the fact that Arrows have a categorical basis, and no one in math thinks Applicative is interesting, it is my understanding that Applicative is generally better understood than Arrow.
Basically you can think of "Category < Arrow < ArrowApply" and "Functor < Applicative < Monad" such that "Category ~ Functor", "Arrow ~ Applicative" and "ArrowApply ~ Monad".
More Concrete Below:
As for other structures to model computation: one can often reverse the direction of the "arrows" (just meaning morphisms here) in categorical constructions to get the "dual" or "co-construction". So, if a monad is defined as
class Functor m => Monad m where
return :: a -> m a
join :: m (m a) -> m a
(okay, I know that isn't how Haskell defines things, but ma >>= f = join $ fmap f ma and join x = x >>= id so it just as well could be)
then the comonad is
class Functor m => Comonad m where
extract :: m a -> a -- this is co-return
duplicate :: m a -> m (m a) -- this is co-join
This thing turns out to be pretty common also. It turns out that Comonad is the basic underlying structure of cellular automata. For completness, I should point out that Edward Kmett's Control.Comonad puts duplicate in a class between functor and Comonad for "Extendable Functors" because you can also define
extend :: (m a -> b) -> m a -> m b -- Looks familiar? this is just the dual of >>=
extend f = fmap f . duplicate
--this is enough
duplicate = extend id
It turns out that all Monads are also "Extendable"
monadDuplicate :: Monad m => m a -> m (m a)
monadDuplicate = return
while all Comonads are "Joinable"
comonadJoin :: Comonad m => m (m a) -> m a
comonadJoin = extract
so these structures are very close together.
All Monads are Arrows (Monad is isomorphic to ArrowApply). In a different way, all Monads are instances of Applicative, where <*> is Control.Monad.ap and *> is >>. Applicative is weaker because it does not guarantee the >>= operation. Thus Applicative captures computations that do not examine previous results and branch on values. In retrospect much monadic code is actually applicative, and with a clean rewrite this would happen.
Extending monads, with recent Constraint kinds in GHC 7.4.1 there can now be nicer designs for restricted monads. And there are also people looking at parameterized monads, and of course I include a link to something by Oleg.
In libraries these structures give rise to different type of computations.
For example Applicatives can be used to implement static effects. With that I mean effects, which are defined at forehand. For example when implementing a state machine, rejecting or accepting an input state. They can't be used to manipulate their internal structure in terms of their input.
The type says it all:
<*> :: f (a -> b) -> f a -> f b
It is easy to reason, the structure of f cannot be depend om the input of a. Because a cannot reach f on the type level.
Monads can be used for dynamic effects. This also can be reasoned from the type signature:
>>= :: m a -> (a -> m b) -> m b
How can you see this? Because a is on the same "level" as m. Mathematically it is a two stage process. Bind is a composition of two function: fmap and join. First we use fmap together with the monadic action to create a new structure embedded in the old one:
fmap :: (a -> b) -> m a -> m b
f :: (a -> m b)
m :: m a
fmap f :: m a -> m (m b)
fmap f m :: m (m b)
Fmap can create a new structure, based on the input value. Then we collapse the structure with join, thus we are able to manipulate the structure from within the monadic computation in a way that depends on the input:
join :: m (m a) -> m a
join (fmap f m) :: m b
Many monads are easier to implement with join:
(>>=) = join . fmap
This is possible with monads:
addCounter :: Int -> m Int ()
But not with applicatives, but applicatives (and any monad) can do things like:
addOne :: m Int ()
Arrows give more control over the input and the output types, but for me they really feel similar to applicatives. Maybe I am wrong about that.
When reading up on type classes I have seen that the relationship between Functors, Applicative Functors, and Monads is that of strictly increasing power. Functors are types that can be mapped over. Applicative Functors can do the same things with certain effects. Monads the same with possibly unrestrictive effects. Moreover:
Every Monad is an Applicative Functor
Every Applicative Functor is a Functor
The definition of the Applicative Functor shows this clearly with:
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
But the definition of Monad is:
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
m >> n = m >>= \_ -> n
fail :: String -> m a
According to Brent Yorgey's great typeclassopedia that an alternative definition of monad could be:
class Applicative m => Monad' m where
(>>=) :: m a -> (a -> m b) -> m b
which is obviously simpler and would cement that Functor < Applicative Functor < Monad. So why isn't this the definition? I know applicative functors are new, but according to the 2010 Haskell Report page 80, this hasn't changed. Why is this?
Everyone wants to see Applicative become a superclass of Monad, but it would break so much code (if return is eliminated, every current Monad instance becomes invalid) that everyone wants to hold off until we can extend the language in such a way that avoids breaking the code (see here for one prominent proposal).
Haskell 2010 was a conservative, incremental improvement in general, standardising only a few uncontroversial extensions and breaking compatibility in one area to bring the standard in line with every existing implementation. Indeed, Haskell 2010's libraries don't even include Applicative — less of what people have come to expect from the standard library is standardised than you might expect.
Hopefully we'll see the situation improve soon, but thankfully it's usually only a mild inconvenience (having to write liftM instead of fmap in generic code, etc.).
Changing the definition of Monad at this point, would have broken a lot of existing code (any piece of code that defines a Monad instance) to be worthwhile.
Breaking backwards-compatibility like that is only worthwhile if there is a large practical benefit to the change. In this case the benefit is not that big (and mostly theoretical anyway) and wouldn't justify that amount of breakage.