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.
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.
In Control.Lens.Lens, there is a function
modifying :: MonadState s m => ASetter s s a b -> (a -> b) -> m ()
which allows the value under a lens on the MonadState state to be transformed by a pure function (a -> b).
However, we may want to allow the transform function to fail in m, requiring it to have type (a -> m b).
I've looked through the lens library for such a function, but I can't find one, so I implemented:
modifyingM l f = use l >>= f >>= assign l
Which does the trick, but I was wondering if there is a function already in the lens library that will do this.
I don't see anything like that. ASetter is defined
type ASetter s t a b = (a -> Identity b) -> s -> Identity t
so it's not powerful enough for the job (and Setter can't do it either). It turns out, on the other hand, that a Lens is a bit stronger than necessary. Let's consider, then, how to do it with a Traversal.
type Traversal s t a b =
forall f. Applicative f => (a -> f b) -> s -> f t
So
Traversal s s a b =
forall f. Applicative f => (a -> f b) -> s -> f s
Which Applicative do we want? m seems like the obvious one to try. When we pass the traversal a -> m b, we get back s -> m s. Great! As usual for lens, we'll actually only require the user to provide an ATraversal, which we can clone.
modifyingM
:: MonadState s m
=> ATraversal s s a b
-> (a -> m b) -> m ()
modifyingM t f = do
s <- get
s' <- cloneTraversal t f s
put s'
That's nice because it only traverses the state once.
Even that is overkill, really. The most natural thing is actually
modifyingM
:: MonadState s m
=> LensLike m s s a b
-> (a -> m b) -> m ()
modifyingM t f = do
s <- get
s' <- t f s
put s'
You can apply that directly to a Traversal, Lens, Iso, or Equality, or use cloneTraversal, cloneLens, cloneIso, or (in lens-4.18 or later) cloneEquality to apply it to the monomorphic variants.
I wonder whether there is a good name for functions with the following signature and implementation (Haskell-notation):
humble :: (a -> a -> b) -> a -> b
humble f x = f x x
It seems somehow related to fold1 (fold with no base case).
As has been mentioned by #4castle in the comments, the function you're looking for is join in Control.Monad. It's type is
join :: Monad m => m (m a) -> m a
The simple reader monad is (->) r,so if we set m ~ (->) r, we get
join :: (->) r ((->) r a) -> (->) r a
or, more concisely,
join :: (r -> r -> a) -> (r -> a)
which is what you want.
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