I'm pretty sure this has a simple solution but it eludes me and I cannot seem to find a straight answer.
Normally, when applying liftA2
assuming the binary function has already been lifted once, the signature looks like this:
liftA2' :: (Applicative f1, Applicative f)
=> (f a -> f b -> f c) -> f1 (f a) -> f1 (f b) -> f1 (f c)
Is it possible to apply the "inverse" of, for example liftA2
such as:
inverseA2 :: (Applicative f, Applicative f1)
=> (f a -> f b -> f c) -> f (f1 a) -> f (f1 b) -> f (f1 c)
As a concrete example, I would like to obtain the function:
f :: ([a] -> [b] -> [c]) -> [Maybe a] -> [Maybe b] -> [Maybe c]
One way would be to resort to "pack" each argument [Maybe a] -> Maybe [a]
and "unpack" Maybe [a] -> [Maybe a]
the result of applying a normal liftA2
. I would like to avoid that since, as you can imagine, packing is destructive (e.g. pack [Just 1, Nothing, Just 2] == Nothing
).
Update: as @user2407038 pointed out, in order for f
to apply the given function you necessarily need a function along the lines of [Maybe a] -> [a]
which does lose information. So for these two particular functors there is no apparent way to satisfy the additional requirement posed. But for any other two functors f
, f1
which have an invertible function forall a . f a -> f1 a
the answer accepted fits perfectly as a solution to this question.