The type signature for >>= is the following:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
And the following makes sense to me (it is also one of the monad laws):
(>>=) (Just 1) (id . return) == Just 1
Yet the Prelude gives the following:
Prelude> :t (>>=) (Just 1) id
(>>=) (Just 1) id :: Num (Maybe b) => Maybe b
I would have expected the Prelude to return some error as the type signature on id is (a -> a) as opposed to Monad m => (a -> m b).
Is there a great way to understand what is going on here? Is there any use for (>>=) (Just 1) id?
The type of id is c -> c (using a different letter so not to conflict with a and b that occur in the type of >>=). We can unify c -> c with a -> Maybe b if we pick c = a = Maybe b.
So this means that >>= in your example is used at type:
(>>=) :: Maybe (Maybe b) -> (Maybe b -> Maybe b) -> Maybe b
Now you have
(>>=) (Just 1) id
For Just 1 to be of type Maybe (Maybe b), Maybe b must be in Num (because then 1 can be interpreted as Maybe b).
Related
Looking at Haskell's bind:
Prelude> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
I was confused by the following example:
Prelude> let same x = x
Prelude> [[1]] >>= \x -> same x
[1]
Looking at >>='s signature, how does \x -> same x type check with a -> m b?
I would've expected \x -> same x to have produced a [b] type, since the Monad m type here is [], as I understand.
You say
I would've expected \x -> same x to have produced a [b] type, since the Monad m type here is [], as I understand.
and so it does because it is.
We have
[[1]] >>= \ x -> same x
=
[[1]] >>= \ x -> x
[[Int]] [Int] -> [Int] :: [Int]
[] [Int] [Int] -> [] Int :: [] Int
m a a m b m b
Sometimes [] is describing a kind of "nondeterminism" effect. Other times, [] is describing a container-like data structure. The fact that it's difficult to tell the difference between which of these two purposes is being served is a feature of which some people are terribly proud. I'm not ready to agree with them, but I see what they're doing.
Looking at >>='s signature, how does \x -> same x type check with a -> m b?
It's actually very simple. Look at the type signatures:
same :: x -> x
(>>=) :: Monad m => m a -> (a -> m b) -> m b
(>>= same) :: Monad m => m a -> (a -> m b) -> m b
|________|
|
x -> x
Therefore:
x := a
-- and
x := m b
-- and by transitivity
a := x := m b
-- or
a := m b
Hence:
(>>= same) :: Monad m => m (m b) -> m b
This is just the join function from the Control.Monad module, and for the list monad it is the same as the concat function. Thus:
[[1]] >>= \x -> same x
-- is the same as the following via eta reduction
[[1]] >>= same
-- is the same as
(>>= same) [[1]]
-- is the same as
join [[1]]
-- is the same as
concat [[1]]
-- evaluates to
[1]
I would've expected \x -> same x to have produced a [b] type, since the Monad m type here is [], as I understand.
Indeed, it does. The \x -> same x function which has the type x -> x is specialized to the type [b] -> [b] as I explained above. Hence, (>>= same) is of the type [[b]] -> [b] which is the same as the concat function. It flattens a list of lists.
The concat function is a specialization of the join function which flattens a nested monad.
It should be noted that a monad can be defined in terms of either >>= or fmap and join. To quote Wikipedia:
Although Haskell defines monads in terms of the return and >>= functions, it is also possible to define a monad in terms of return and two other operations, join and fmap. This formulation fits more closely with the original definition of monads in category theory. The fmap operation, with type Monad m => (a -> b) -> m a -> m b, takes a function between two types and produces a function that does the “same thing” to values in the monad. The join operation, with type Monad m => m (m a) -> m a, “flattens” two layers of monadic information into one.
The two formulations are related as follows:
fmap f m = m >>= (return . f)
join n = n >>= id
m >>= g ≡ join (fmap g m)
Here, m has the type Monad m => m a, n has the type Monad m => m (m a), f has the type a -> b, and g has the type Monad m => a -> m b, where a and b are underlying types.
The fmap function is defined for any functor in the category of types and functions, not just for monads. It is expected to satisfy the functor laws:
fmap id ≡ id
fmap (f . g) ≡ (fmap f) . (fmap g)
The return function characterizes pointed functors in the same category, by accounting for the ability to “lift” values into the functor. It should satisfy the following law:
return . f ≡ fmap f . return
In addition, the join function characterizes monads:
join . fmap join ≡ join . join
join . fmap return ≡ join . return = id
join . fmap (fmap f) ≡ fmap f . join
Hope that helps.
As a few people have commented, you've found a really cute property about monads here. For reference, let's look at the signature for bind:
:: Monad m => m a -> (a -> m b) -> m b
In your case, the type a === m b as you have a [[a]] or m (m a). So, if you rewrite the signature of the above bind operation, you get:
:: Monad m => m (m b) -> ((m b) -> m b) -> m b
I mentioned that this is cute, because by extension, this works for any nested monad. e.g.
:: [[b]] -> ([b] -> [b]) -> [b]
:: Maybe (Maybe b) -> (Maybe b -> Maybe b) -> Maybe b
:: Reader (Reader b) -> (Reader b -> Reader b) -> Reader b
If you look at the function that get's applied here, you'll see that it's the identity function (e.g. id, same, :: forall a. a -> a).
This is included in the standard libraries for Haskell, as join. You can look at the source here on hackage. You'll see it's implemented as bind id, or \mma -> mma >>= id, or (=<<) id
As you say m is []. Then a is [Integer] (ignoring the fact that numbers are polymorphic for simplicity's sake) and b is Integer. So a -> m b becomes [Integer] -> [Integer].
First: we should use the standard version of same, it is called id.
Now, let's rename some type variables
id :: (a'' ~ a) => a -> a''
What this means is: the signature of id is that of a function mapping between two types, with the extra constraint that both types be equal. That's all – we do not require any particular properties, like “being flat”.
Why the hell would I write it this way? Well, if we also rename some of the variables in the bind signature...
(>>=) :: (Monad m, a'~m a, a''~m b) => a' -> (a -> a'') -> a''
...then it is obvious how we can plug the id, as the type variables have already been named accordingly. The type-equality constraint a''~a from id is simply taken to the compound's signature, i.e.
(>>=id) :: (Monad m, a'~m a, a''~m b, a''~a) => a' -> a''
or, simplifying that,
(>>=id) :: (Monad m, a'~m a, m b~a) => a' -> m b
(>>=id) :: (Monad m, a'~m (m b)) => a' -> m b
(>>=id) :: (Monad m) => m (m b) -> m b
So what this does is, it flattens a nested monad to a single application of that same monad. Quite simple, and as a matter of fact this is one the “more fundamental” operation: mathematicians don't define the bind operator, they instead define two morphisms η :: a -> m a (we know that, it's return) and μ :: m (m a) -> m a – yup, that's the one you've just discovered. In Haskell, it's called join.
The monad here is [a] and the example is pointlessly complicated. This’ll be clearer:
Prelude> [[1]] >>= id
[1]
just as
Prelude> [[1]] >>= const [2]
[2]
i.e. >>= is concatMap and is concat when used with id.
I recently stumbled across Djinn and was briefly playing around with it to try to see whether it would be useful in my everyday coding workflow. I was excited to see that Djinn had monads and tried to see whether it might be able to find some cool functions.
Djinn did in fact work some wonders. The type signature of the initially (at least to me) unintuitive function >>= (>>=) is Monad m => ((a -> m b) -> m a) -> (a -> m b) -> m b. Djinn was able to immediately demystify this by stating
Djinn> f ? Monad m => ((a -> m b) -> m a) -> (a -> m b) -> m b
f :: (Monad m) => ((a -> m b) -> m a) -> (a -> m b) -> m b
f a b = a b >>= b
Unfortunately, Djinn can't seem to find other standard functions on monads, despite knowing about the Monad typeclass.
join (which should be join = (>>= id) or in Djinn's more verbose syntax join a = a >>= (\x -> x))
Djinn> join ? Monad m => m (m a) -> m a
-- join cannot be realized.
liftM (which should be liftM f = (>>= (return . f)) or in Djinn's more verbose syntax liftM a b = b >>= (\x -> return (a x)))
Djinn> liftM ? Monad m => (a -> b) -> m a -> m b
-- liftM cannot be realized.
Even the basic return :: Monad m => m a -> m (m a) cannot be found by Djinn or return :: Monad m => (a, b) -> m (a, b).
Djinn> f ? Monad m => (a, b) -> m (a, b)
-- f cannot be realized.
Djinn knows how to use \ to construct anonymous functions so why is this the case?
My rough suspicion is that perhaps Djinn has a simplistic notion of typeclass and somehow treats m a as "fixed" so that m (a, b) is not seen as a case of m a, but I have no idea how to make that any more concrete than its current hand-wavy form or whether that intuition is correct.
Supporting type classes properly looks a lot like supporting rank-2 types; compare:
join :: Monad m
=> m (m a) -> m a
vs:
join :: (forall a. a -> m a)
-> (forall a b. m a -> (a -> m b) -> m b)
-> m (m a) -> m a
Unfortunately, the techniques Djinn uses don't handle rank-2 types at all. If you float the foralls so that Djinn can process it, suddenly what you get instead are concrete choices:
join :: (b -> m b)
-> (m c -> (c -> m d) -> m d)
-> m (m a) -> m a
which looks a lot less like you could implement it! If you tell Djinn which instantiations to use, it does a lot better, of course.
join :: (b -> m b)
-> (m (m a) -> (m a -> m a) -> m a)
-> m (m a) -> m a
For this one, Djinn will give the right implementation. ...but then, that's cheating.
New to Haskell, and am trying to figure out this Monad thing. The monadic bind operator -- >>= -- has a very peculiar type signature:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
To simplify, let's substitute Maybe for m:
(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
However, note that the definition could have been written in three different ways:
(>>=) :: Maybe a -> (Maybe a -> Maybe b) -> Maybe b
(>>=) :: Maybe a -> ( a -> Maybe b) -> Maybe b
(>>=) :: Maybe a -> ( a -> b) -> Maybe b
Of the three the one in the centre is the most asymmetric. However, I understand that the first one is kinda meaningless if we want to avoid (what LYAH calls boilerplate code). However, of the next two, I would prefer the last one. For Maybe, this would look like:
When this is defined as:
(>>=) :: Maybe a -> (a -> b) -> Maybe b
instance Monad Maybe where
Nothing >>= f = Nothing
(Just x) >>= f = return $ f x
Here, a -> b is an ordinary function. Also, I don't immediately see anything unsafe, because Nothing catches the exception before the function application, so the a -> b function will not be called unless a Just a is obtained.
So maybe there is something that isn't apparent to me which has caused the (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b definition to be preferred over the much simpler (>>=) :: Maybe a -> (a -> b) -> Maybe b definition? Is there some inherent problem associated with the (what I think is a) simpler definition?
It's much more symmetric if you think in terms the following derived function (from Control.Monad):
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
(f >=> g) x = f x >>= g
The reason this function is significant is that it obeys three useful equations:
-- Associativity
(f >=> g) >=> h = f >=> (g >=> h)
-- Left identity
return >=> f = f
-- Right identity
f >=> return = f
These are category laws and if you translate them to use (>>=) instead of (>=>), you get the three monad laws:
(m >>= g) >>= h = m >>= \x -> (g x >>= h)
return x >>= f = f x
m >>= return = m
So it's really not (>>=) that is the elegant operator but rather (>=>) is the symmetric operator you are looking for. However, the reason we usually think in terms of (>>=) is because that is what do notation desugars to.
Let us consider one of the common uses of the Maybe monad: handling errors. Say I wanted to divide two numbers safely. I could write this function:
safeDiv :: Int -> Int -> Maybe Int
safeDiv _ 0 = Nothing
safeDiv n d = n `div` d
Then with the standard Maybe monad, I could do something like this:
foo :: Int -> Int -> Maybe Int
foo a b = do
c <- safeDiv 1000 b
d <- safeDiv a c -- These last two lines could be combined.
return d -- I am not doing so for clarity.
Note that at each step, safeDiv can fail, but at both steps, safeDiv takes Ints, not Maybe Ints. If >>= had this signature:
(>>=) :: Maybe a -> (a -> b) -> Maybe b
You could compose functions together, then give it either a Nothing or a Just, and either it would unwrap the Just, go through the whole pipeline, and re-wrap it in Just, or it would just pass the Nothing through essentially untouched. That might be useful, but it's not a monad. For it to be of any use, we have to be able to fail in the middle, and that's what this signature gives us:
(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
By the way, something with the signature you devised does exist:
flip fmap :: Maybe a -> (a -> b) -> Maybe b
The more complicated function with a -> Maybe b is the more generic and more useful one and can be used to implement the simple one. That doesn't work the other way around.
You can build a a -> Maybe b function from a function f :: a -> b:
f' :: a -> Maybe b
f' x = Just (f x)
Or, in terms of return (which is Just for Maybe):
f' = return . f
The other way around is not necessarily possible. If you have a function g :: a -> Maybe b and want to use it with the "simple" bind, you would have to convert it into a function a -> b first. But this doesn't usually work, because g might return Nothing where the a -> b function needs to return a b value.
So generally the "simple" bind can be implemented in terms of the "complicated" one, but not the other way around. Additionally, the complicated bind is often useful and not having it would make many things impossible. So by using the more generic bind monads are applicable to more situations.
The problem with the alternative type signature for (>>=) is that it only accidently works for the Maybe monad, if you try it out with another monad (i.e. List monad) you'll see it breaks down at the type of b for the general case. The signature you provided doesn't describe a monadic bind and the monad laws can't don't hold with that definition.
import Prelude hiding (Monad, return)
-- assume monad was defined like this
class Monad m where
(>>=) :: m a -> (a -> b) -> m b
return :: a -> m a
instance Monad Maybe where
Nothing >>= f = Nothing
(Just x) >>= f = return $ f x
instance Monad [] where
m >>= f = concat (map f m)
return x = [x]
Fails with the type error:
Couldn't match type `b' with `[b]'
`b' is a rigid type variable bound by
the type signature for >>= :: [a] -> (a -> b) -> [b]
at monadfail.hs:12:3
Expected type: a -> [b]
Actual type: a -> b
In the first argument of `map', namely `f'
In the first argument of `concat', namely `(map f m)'
In the expression: concat (map f m)
The thing that makes a monad a monad is how 'join' works. Recall that join has the type:
join :: m (m a) -> m a
What 'join' does is "interpret" a monad action that returns a monad action in terms of a monad action. So, you can think of it peeling away a layer of the monad (or better yet, pulling the stuff in the inner layer out into the outer layer). This means that the 'm''s form a "stack", in the sense of a "call stack". Each 'm' represents a context, and 'join' lets us join contexts together, in order.
So, what does this have to do with bind? Recall:
(>>=) :: m a -> (a -> m b) -> m b
And now consider that for f :: a -> m b, and ma :: m a:
fmap f ma :: m (m b)
That is, the result of applying f directly to the a in ma is an (m (m b)). We can apply join to this, to get an m b. In short,
ma >>= f = join (fmap f ma)
Why does partial application of functions with different signatures work?
Take Control.Monad.join as an example:
GHCi> :t (=<<)
(=<<) :: Monad m => (a -> m b) -> m a -> m b
GHCi> :t id
id :: a -> a
GHCi> :t (=<<) id
(=<<) id :: Monad m => m (m b) -> m b
Why does it accepts id :: a -> a in place of (a -> m b) argument, as they are obviously different ?
=<<'s type signature says that the first argument is a function from an a (anything) to a monad of b.
Well, m b counts as anything, right? So we can just substitute in m b for every a:
(=<<) :: Monad m => (m b -> m b) -> m (m b) -> m b
ids type says that it is a function from anything to the same anything. So if we sub in m b (not forgetting the monad constraint), we get:
id :: Monad m => m b -> m b
Then you can see that the types match.
Some useful concepts to use here:
Any type with a variable a can be converted into a different type by replacing every instance of a with any other type t. So if you have the type a -> b -> c, you can obtain the type a -> d -> c or the type a -> b -> Int by replacing b with d or c with Int respectively.
Any two types that can be converted to each other by replacement are equivalent. For example, a -> b and c -> d are equivalent (a ~ c, b ~ d).
If a type t can be converted to a type t', but t' can't be converted back to t, then we say that t' is a specialization of t. For example, a -> a is a specialization of a -> b.
Now, with these very useful concepts, the answer to your question is very simple: even if the function's "native" types don't match exactly, they are compatible because they can be rewritten or specialized to get that exact match. Matt Fenwick's answer shows specializations that do it for this case.
It tries to unify a with m b, and simply decides that a must be m b, so the type of (=<<) (under the assumption a ~ m b) is Monad m => (mb -> m b) -> m (m b) -> m b, and once you apply it to id, you are left with Monad m => m (m b) -> m b.
The join utility function is defined as:
join :: (Monad m) => m (m a) -> m a
join x = x >>= id
Given that the type of >>= is Monad m => m a -> (a -> m b) -> m b and id is a -> a, how can that function also be typed as a -> m b as it must be in the definition above? What are m and b in this case?
The as in the types for >>= and id aren't necessarily the same as, so let's restate the types like this:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
id :: c -> c
So we can conclude that c is the same as a after all, at least when id is the second argument to >>=... and also that c is the same as m b. So a is the same as m b. In other words:
(>>= id) :: Monad m => m (m b) -> m b
dave4420 hits it, but I think the following remarks might still be useful.
There are rules that you can use to validly "rewrite" a type into another type that's compatible with the original. These rules involve replacing all occurrences of a type variable with some other type:
If you have id :: a -> a, you can replace a with c and get id :: c -> c. This latter type can also be rewritten to the original id :: a -> a, which means that these two types are equivalent. As a general rule, if you replace all instances of type variable with another type variable that occurs nowhere in the original, you get an equivalent type.
You can replace all occurrences of a type variable with a concrete type. I.e., if you have id :: a -> a, you can rewrite that to id :: Int -> Int. The latter however can't be rewritten back to the original, so in this case you're specializing the type.
More generally than the second rule, you can replace all occurrences of a type variable any type, concrete or variable. So for example, if you have f :: a -> m b, you can replace all occurrences of a with m b and get f :: m b -> m b. Since this one can't be undone either, it's also a specialization.
That last example shows how id can be used as the second argument of >>=. So the answer to your question is that we can rewrite and derive types as follows:
1. (>>=) :: m a -> (a -> m b) -> m b (premise)
2. id :: a -> a (premise)
3. (>>=) :: m (m b) -> (m b -> m b) -> m b (replace a with m b in #1)
4. id :: m b -> m b (replace a with m b in #2)
.
.
.
n. (>>= id) :: m (m b) -> m b (indirectly from #3 and #4)