Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Haskell, are there aliases for (liftM . liftM), (liftM . liftM . liftM), etc?

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]
like image 393
Lay González Avatar asked Feb 23 '15 01:02

Lay González


People also ask

What is <*> called in Haskell?

(<*>) 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 are monads in Haskell?

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.

What are Functors Haskell?

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.

What does LIFT mean in Haskell?

From HaskellWiki. Lifting is a concept which allows you to transform a function into a corresponding function within another (usually more general) setting.


1 Answers

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.

Digression:

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 >>=.

Your functions and operators

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.

like image 116
AndrewC Avatar answered Oct 06 '22 01:10

AndrewC