Put two monadic values into a pair and return it
I am playing with Parsec and I want to combine two parsers into one with the result put in a pair, and then feed i开发者_C百科t another function to operate on the parse result to write something like this:
try (pFactor <&> (char '*' *> pTerm) `using` (*))
So I wrote this:
(<&>) :: (Monad m) => m a -> m b -> m (a, b)
pa <&> pb = do
a <- pa
b <- pb
return (a, b)
And
using :: (Functor f) => f (a, b) -> (a -> b -> c) -> f c
p `using` f = (uncurry f) <$> p
Is there anything similar to (<&>) which has been implemented somewhere? Or could this be written pointfree? I tried fmap (,)
but it seems hard to match the type.
Better than <&>
or liftM2
would be
(,) <$> a <*> b
since Applicative style seems to be gaining popularity and is very succinct. Using applicative style for things like this will eliminate the need for <&>
itself, since it is much clearer than (,) <$> a <*> b
.
Also this doesn't even require a monad - it will work for Applicatives too.
Is there anything similar to (<&>) which has been implemented somewhere? Or could this be written pointfreely? I tried fmap (,) but it seems hard to match the type.
I don't now if it's implemented anywhere, but <&>
should be the same as liftM2 (,)
. The difference to fmap
is, that liftM2
lifts a binary function into the monad.
Using applicative style, there is no need to put the intermediate results into a tuple just to immediately apply an uncurried function. Just apply the function "directly" using <$>
and <*>
.
try ((*) <$> pFactor <*> (char '*' *> pTerm))
In general, assuming sane instances of Monad
and Applicative
,
do x0 <- m0
x1 <- m1
...
return $ f x0 x1 ...
is equivalent to
f <$> m0 <*> m1 <*> ...
except that the latter form is more general and only requires an Applicative
instance. (All monads should also be applicative functors, although the language does not enforce this).
Note, that if you go the opposite direction from Applicative
you'll see that the way you want to combine parsers fits nicely into Arrow paradigm and Arrow parsers implementation.
E.g.:
import Control.Arrow
(<&>) = (&&&)
p `using` f = p >>^ uncurry f
Yes, you could use applicative style but I don't believe that answers either of your questions.
Is there some already defined combinator that takes two arbitrary monads and sticks their value types in a pair and then sticks that pair in the context?
Not in any of the standard packages.
Can you do that last bit point free?
I'm not sure if there is a way to make a curried function with an arity greater than 1 point free. I don't think there is.
Hope that answers your questions.
精彩评论