I'm trying to do what must be blindingly obvious in Haskell, which is go from Just [1]
and Just [2]
to Just [1, 2]
. However I can't find anything online as I keep finding related but unhelpful pages. So, how do you achieve this?
You can use liftA2 (++)
:
liftA2 (++) :: Maybe [a] -> Maybe [a] -> Maybe [a]
liftA2
just lifts a binary function into an Applicative
. Applicative
s were designed for lifting functions of arbitrary arguments in a context, so they're perfect for this. In this case, the Applicative
we're using is Maybe
. To see how this works, we can look at the definition:
liftA2 :: (Applicative f) => (a -> b -> c) -> f a -> f b -> f c
liftA2 f a b = f <$> a <*> b
(<$>)
just lifts any function on pure values to one operating inside f
: (a -> b) -> f a -> f b
. (It's just an alias for fmap
, if you're familiar with Functor
s.) For Maybe
:
_ <$> Nothing = Nothing
f <$> Just x = Just (f x)
(<*>)
is a bit trickier: it applies a function inside f
to a value inside f
: f (a -> b) -> f a -> f b
. For Maybe
:
Just f <*> Just x = Just (f x)
_ <*> _ = Nothing
(In fact, f <$> x
is the same thing as pure f <*> x
, which is Just f <*> x
for Maybe
.)
So, we can expand the definition of liftA2 (++)
:
liftA2 (++) a b = (++) <$> a <*> b
-- expand (<$>)
liftA2 (++) (Just xs) b = Just (xs ++) <*> b
liftA2 (++) _ _ = Nothing
-- expand (<*>)
liftA2 (++) (Just xs) (Just ys) = Just (xs ++ ys)
liftA2 (++) _ _ = Nothing
Indeed, we can use these operators to lift a function of any number of arguments into any Applicative
, just by following the pattern of liftA2
. This is called applicative style, and is very common in idiomatic Haskell code. In this case, it might even be more idiomatic to use it directly by writing (++) <$> a <*> b
, if a
and b
are already variables. (On the other hand, if you're partially applying it — say, to pass it to a higher-order function — then liftA2 (++)
is preferable.)
Every Monad
is an Applicative
, so if you ever find yourself trying to "lift" a function into a context, Applicative
is probably what you're looking for.
To expand the solution to a list of Just
s, you could use
fmap join $ sequence [Just[1],Just[2],Just[3]]
-- Just [1,2,3]
while @ehird's answer is great, I would have used a noobish solution in the form:
mergeJust a b = do
a' <- a
b' <- b
return (a' ++ b')
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