(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
bind :: Monad m => m a -> (a -> m b) -> m b
-- how do you use >=> to write bind?
I am absolutely so confused, I understand how both of these works but I cant even get started.
I tried all the following alternatives:
bind1 a b = (b a)
bind2 a b = (a >=> b)
bind3 a b = (b >=> a)
bind4 a b = (a b)
but every single attempt raises an error. Where can i possibly start on this question?
Since >>= has 2 parameters, and >=> has 3, how can I use >=> to write >>= when there is 1 less parameter?
First I'd suggest renaming the type parameters so the final result matches:
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
bind :: Monad m => m a -> (a -> m c) -> m c
Now we have a b -> m c in the first signature and a -> m c in the second; that suggests renaming also a to b:
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
bind :: Monad m => m b -> (b -> m c) -> m c
That leaves the main difference as having an extra argument a. But we evidently don't need that, so we might as well specialize it to the information-less type () (or any other single-value type):
(>=>) :: Monad m => (() -> m b) -> (b -> m c) -> (() -> m c)
bind :: Monad m => m b -> (b -> m c) -> m c
() -> m x is actually isomorphic to m x alone:
addDummyArg :: a -> (() -> a)
addDummyArg c () = c
rmDummyArg :: (() -> a) -> a
rmDummyArg f = f ()
And it's just a matter of using those conversion functions to adapt the functions to each other.
Since >>= has 2 parameters, and >=> has 3, how can I use >=> to write >>= when there is 1 less parameter?
Each function in Haskell has one parameter. You can interpret >=> , as a function that has as first parameter something of type a -> m b and the second something of b -> m c, the a -> m c is the "result" function.
What you here can do is manipulate the first parameter of bind into a function that accepts a parameter, and then provide that parameter, something like:
bind :: Monad m => m a -> (a -> m b) -> m b
bind ma f = (const ma >=> f) undefined
Here with const ma, we thus create a function that takes a parameter we do not care about, then we construct an a -> m c by using >=> and we call it with undefined (or some other value) to produce the m c value.
Related
Functor has
(a -> b) -> m a -> m b
Applicative has
f (a -> b) -> f a -> f b
Monad has
m a -> (a -> m b) -> m b
But, Is there extended monad type that has
m a -> m (a -> m b) -> m b
or
m (a -> m b) -> m a -> m b
?
A Monad constraint is sufficient to implement a (sensible) function with that type signature:
foo :: Monad m => m (a -> m b) -> m a -> m b
foo mf ma = do
f <- mf
a <- ma
f a
or, if you prefer:
foo' :: Monad m => m (a -> m b) -> m a -> m b
foo' mf ma = mf >>= \f -> ma >>= f
This means that your proposed operation, even though it looks like a generalization of the usual >>= bind operation, isn't actually a generalization. Any >>= operation can be written in terms of foo, and any foo operation can be written in terms of >>=, so they are operations of equivalent "power".
In contrast, the other operations are not of equivalent power. Any applicative operation <*> can be written in terms of >>= and return, but you can't in general implement >>= in terms of <*>, so >>= is a strictly more powerful operation, etc.
I have recently started learning Haskell, and I was trying to do the following function composition (join . mapM) but got some weird types out of this function that I don't understand. I thought that either GHC would assume that t == m in the mapM type and the output of mapM would become m (m b) which would be join-able or it would not and this would error out because of type mismatch. Instead the following happened:
mapM :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)
join :: Monad m => m (m a) -> m a
join . mapM :: Traversable t => (a -> t a -> b) -> t a -> t b
I don't understand how this is possible. The way I understand it, function composition should use the inputs of the first (or the second depending how you look at it) function and the outputs of the second function. But here the expected input function for mapM changes from a unary function to a binary function and I have no clue why. Even if GHC can't just make the assumption that t == m like I did, which I half expected, it should error out because of type mismatch, not change the input function type, right? What is happening here?
First you specialize mapM to:
mapM' :: Traversable t => (a -> x -> b) -> t a -> x -> t b
(since (->) x is a monad)
Then you specialize it further to:
mapM'' :: Traversable t => (a -> t a -> b) -> t a -> t a -> t b
(we're just fixing the x to be t a)
Finally we specialize join appropriately:
join' :: (x -> x -> r) -> x -> r
(again, (->) x is a monad)
And hopefully it becomes more apparent why the composition join' . mapM'' is
join' . mapM'' :: Traversable t => (a -> t a -> b) -> t a -> t b
Maybe the following will be more illuminating, instead :
flip mapT :: (Traversable t, Monad m) => t a -> (a -> m b) -> t (m b)
sequenceA :: (Traversable t, Monad m) => t (m b) -> m (t b)
flip mapM :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b)
flip liftM :: Monad m => m a -> (a -> m b) -> m (m b)
join :: Monad m => m (m b) -> m b
(join .) . flip liftM :: Monad m => m a -> (a -> m b) -> m b
(>>=) :: Monad m => m a -> (a -> m b) -> m b
(using some more specialized types than the most general ones, here and there; also with the renamed mapT f = runIdentity . traverse (Identity . f)).
Your specific question is less interesting. Type derivation is a fully mechanical process. Some entities must be compatible for the whole expression to make sense, so their types must unify:
(join . mapM) a_mb x = -- a_mb :: a -> m b
= join (mapM a_mb) x
= join ta_mtb x -- ta_mtb :: t a -> m (t b)
To join a function is to call it twice,
= ta_mtb x x
which means x is a t a and so m is t a ->:
x :: t a
ta_mtb :: t a -> m (t b)
----------------------------
ta_mtb x :: m (t b)
~ t a -> t b
x :: t a
----------------------------
ta_mtb x x :: t b
thus a_mb :: a -> m b ~ a -> t a -> b.
I'm looking for a function or operator in Haskell that is effectively a Monad equivalent of the Applicative operator <*> that applies a monadic action rather than a bare function, that is instead of this:
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
I'm looking for something that looks like this:
... :: Monad m => m (a -> m b) -> m a -> m b
I can't believe that this isn't a standard function, but I can't see anything that matches. Am I missing something?
This will be a simple composition of two other basic monad functions, namely join and ap; since:
ap :: Monad m => m (a -> b) -> m a -> m b
join :: Monad m => m (m a) -> m a
we get:
(join .) . ap :: Monad m => m (a -> m b) -> m a -> m b
as well as:
(join .) . (<*>) :: Monad m => m (a -> m b) -> m a -> m b
or, using only bind operator, another construct would be:
(. (>>=)) . (>>=) :: Monad m => m (a -> m b) -> m a -> m b
In Haskell's Monads, I can easily define the operator (>=>) as :
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
f >=> g = \x -> f x >>= g
I also know that (>>=) can be expressed using (>=>): Let's call (>>=) as (..):
(..) :: Monad m => m a -> (a -> m b) -> m b
m .. k = m >=> \_ -> k
However something is not right ... could someone point what?
The idea of using a constant function (that is, \_ -> -- etc.) to make a function out of the argument which isn't a function so that you can pass it to (>=>) is sound. There are just two issues. Firstly, you are doing it to the wrong argument, as the one which isn't a function is m:
GHCi> :t \m k -> (\_ -> m) >=> k
\m k -> (\_ -> m) >=> k :: Monad m => m b -> (b -> m c) -> a -> m c
Secondly, (>=>) gives you a function (of type a -> m c in the demo just above). You have to apply it to something to get a result type that matches the one of (>>=). As that argument is irrelevant (you are ultimately feeding it to a constant function) you can just use ():
GHCi> :t \m k -> ((\_ -> m) >=> k) ()
\m k -> ((\_ -> m) >=> k) () :: Monad m => m b -> (b -> m c) -> m c
And that's it. I find it slightly prettier to use the const function rather than writing \_ ->, and so I would write it as:
(>>..) :: Monad m => m a -> (a -> m b) -> m b
m >>.. k = (const m >=> k) ()
The solution is the following:
(..) :: Monad m => m a -> (a -> m b) -> m b
m .. k =
(const m >=> k) undefined
Using const we're lifting an operation of type m a to whatever -> m a. This lifted version does not give a damn, what we pass to it so it might as well be the undefined.
id :: a -> a
liftM2 :: (Monad m) => (a -> b -> c) -> m a -> m b -> m c
ap :: (Monad m) => m (a -> b) -> m a -> m b
ap = liftM2 id
Could you help explain how the type of ap is inferred when liftM2 is applied to id? Moreover, is it valid to ask the equivalent question but more specifically how (a -> b -> c) -> m a is reduced to m (a -> b) in this case?
Lets try to find out what liftM2 id's type should be. First of all, we change the type parameter in id, so that we can fix this a little bit easier.
id :: x -> x
liftM2 :: (Monad m) => (a -> b -> c) -> m a -> m b -> m c
Next, we add additional parentheses in liftM2 and remember that a -> b -> c is actually a -> (b -> c):
id :: x -> x
liftM2 :: (Monad m) => (a -> (b -> c)) -> m a -> (m b -> m c)
Now we shift x -> x to line it up with other types in liftM2:
id :: x -> x
liftM2 :: (Monad m) => (a -> (b -> c)) -> m a -> (m b -> m c)
Ok. This tells us that a ~ (b -> c) in liftM2 id, or:
id :: (b -> c) -> (b -> c)
liftM2 :: (Monad m) => ((b -> c) -> (b -> c))
-> m (b -> c) -> (m b -> m c)
Now we can use those specialized versions:
liftM2 id :: Monad m => m (b -> c) -> (m b -> m c)
We drop the superfluous parentheses and end up with the correct type:
liftM2 id :: Monad m => m (b -> c) -> m b -> m c
id has the type a -> a. The first question is how can we unify a -> a with the type of liftM2's argument, (a -> b -> c)? The trick is to replace the a in a -> a with (a -> b) giving us (a -> b) -> (a -> b) or, equivalently, (a -> b) -> a -> b. (As a neat side note, this is the type of $, which means $ is just id with a restricted type!)
Now we combine (a -> b) -> a -> b with liftM2's whole type:
Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
We replace a1 with a -> b, a2 with a and r with b giving us:
Monad m => ((a -> b) -> a -> b) -> m (a -> b) -> m a -> m b
Finally, once we apply liftM2 to id, the result has the same type minus the first argument:
liftM2 id :: Monad m => m (a -> b) -> m a -> m b
And there we are: the type of ap.
A good intuition for this is based on my earlier observation about $. $ is the normal function application operator; ap is function application lifted over a monad. It makes sense that liftM2 ($) gives you ap because that's what ap fundamentally means... and id is just a version of $ with a more general type.