In Haskell, is there any alias for (liftM . liftM), (liftM . liftM . liftM) etc?
So that I don't have to be so verbose, e.g.:
(liftM . liftM) (+ 1) [Just 1, Just 2] = [Just 2, Just 3]
(liftM2 . liftM2) (+) [Just 1] [Just 2] = [Just 3]
(<*>) is just a modified function application, so you can either read it as "ap" or "apply", or elide it entirely the way you would normal function application. (<*>) also roughly generalizes zipWith on lists, so you can read it as "zip functors with", similarly to reading fmap as "map a functor with".
What is a Monad? A monad is an algebraic structure in category theory, and in Haskell it is used to describe computations as sequences of steps, and to handle side effects such as state and IO. Monads are abstract, and they have many useful concrete instances. Monads provide a way to structure a program.
Functor in Haskell is a kind of functional representation of different Types which can be mapped over. It is a high level concept of implementing polymorphism. According to Haskell developers, all the Types such as List, Map, Tree, etc. are the instance of the Haskell Functor.
From HaskellWiki. Lifting is a concept which allows you to transform a function into a corresponding function within another (usually more general) setting.
There isn't such a thing as that in base, but well done for asking the most entertaining question for me on Stack Overflow for some time.
Functors and Applicative functors are closed under composition (which certainly isn't the case in general for monads, thus the need for monad transformers), which is why liftA2.liftA2
works here, and liftM2
is usually just liftA2
, especially now Applicative is becoming a superclass of Monad.
You can use the composition newtype in Data.Functor.Compose package to compose an Applicative, but you can make new applicatives out of old ones in other ways too - I strongly recommend Gershom Bazerman's post "Abstracting with Applicatives" in the Comonad Reader for folk that want to understand how beautiful a combined Applicative structure is compared to a monad transformer stack - I'm now always on the lookout for making things just Applicative rather than monadic where I can get the functionality I need. Often I can use Applicative to combine all the input stuff into a value I want to output then pipe it directly where i
t's going using >>=
.
Of course there's nothing stopping you defining your own functions:
liftliftA2 :: (Applicative f, Applicative g) =>
(a -> b -> c) -> f (g a) -> f (g b) -> f (g c)
liftliftA2 = liftA2.liftA2
but it's not much shorter than liftA2.liftA2
.
I love your idea to make nested Applicative operators, though, but will switch to increasing the angle brackets rather than repeating the internal operator because <**>
clashes with (<**>) = flip (<*>)
in Control.Applicative, and it's more logical.
import Control.Applicative
(<<$>>) :: (Functor f, Functor g) =>
(a -> b) -> f (g a) -> f (g b)
(<<$>>) = fmap.fmap
(<<*>>) :: (Functor m, Applicative m, Applicative n) =>
m (n (a -> b)) -> m (n a) -> m (n b)
mnf <<*>> mna = (<*>) <$> mnf <*> mna
giving
ghci> (+) <<$>> [Just 5] <<*>> [Just 7,Just 10]
[Just 12,Just 15]
and of course you can keep going:
(<<<$>>>) :: (Functor f, Functor g, Functor h) =>
(a -> b) -> f (g (h a)) -> f (g (h b))
(<<<$>>>) = fmap.fmap.fmap
(<<<*>>>) :: (Functor l,Functor m, Applicative l, Applicative m, Applicative n) =>
l (m (n (a -> b))) -> l (m (n a)) -> l (m (n b))
lmnf <<<*>>> lmna = (<*>) <<$>> lmnf <<*>> lmna
Which lets you do the apparently improbable
ghci> subtract <<<$>>> Right [Just 5,Nothing,Just 10] <<<*>>> Right [Just 100,Just 20]
Right [Just 95,Just 15,Nothing,Nothing,Just 90,Just 10]
but then again, as Gershom Bazerman's article demonstrates, you may well want to nest Applicatives, just as deeply as you might want to nest Monads.
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