I've just written this function which simply takes a pair whose second value is in some monad, and "pulls the monad out" to cover the whole pair.
unSndM :: Monad m => (a, m c) -> m (a, c)
unSndM (x, y) = do y' <- y
return (x, y')
Is there a nicer and/or shorter or point-free or even standard way to express this?
I've got as far as the following, with -XTupleSections turned on...
unSndM' :: Monad m => (a, m c) -> m (a, c)
unSndM' (x, y) = y >>= return . (x,)
Thanks!
If the Traversable
and Foldable
instances for (,) x)
were in the library (and I suppose I must take some blame for their absence)...
instance Traversable ((,) x) where
traverse f (x, y) = (,) x <$> f y
instance Foldable ((,) x) where
foldMap = foldMapDefault
...then this (sometimes called 'strength') would be a specialisation of Data.Traversable.sequence
.
sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)
so
sequence :: (Monad m) => ((,) x) (m a) -> m (((,) x) a)
i.e.
sequence :: (Monad m) => (x, m a) -> m (x, a)
In fact, sequence doesn't really use the full power of Monad
: Applicative
will do. Moreover, in this case, pairing-with-x is linear, so the traverse
does only <$>
rather than other random combinations of pure
and <*>
, and (as has been pointed out elsewhere) you only need m
to have functorial structure.
One minor point: it's possible to write this using only fmap
(no >>=
), so you really only need a Functor
instance:
unSndM :: (Functor f) => (a, f c) -> f (a, c)
unSndM (x, y) = fmap ((,) x) y
This version is a bit more general. To answer your question about a pointfree version, we can just ask pointfree
:
travis@sidmouth% pointfree "unSndM (x, y) = fmap ((,) x) y"
unSndM = uncurry (fmap . (,))
So, yes, an even shorter version is possible, but I personally find uncurry
a bit hard to read and avoid it in most cases.
If I were writing this function in my own code, I'd probably use <$>
from Control.Applicative
, which does shave off one character:
unSndM :: (Functor f) => (a, f c) -> f (a, c)
unSndM (x, y) = ((,) x) <$> y
<$>
is just a synonym for fmap
, and I like that it makes the fact that this is a kind of function application a little clearer.
I haven't seen it written in any Haskell library (though it's probably in category-extras), but it is generally known as the "tensorial strength" of a monad. See:
http://en.wikipedia.org/wiki/Strong_monad
http://comonad.com/reader/2008/deriving-strength-from-laziness/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With