Search code examples
haskelloperatorsterminologyapplicative

<**> is a variant of <*> with the arguments reversed. What does "reversed" mean?


In GHC.Base the description of <**> runs:

A variant of <*> with the arguments reversed.

It is widely known that "reversed" in that case does not mean "flipped" as:

GHCi> [1, 2, 3] <**> [(^2), (+1)]
[1,2,4,3,9,4]
GHCi> [(^2), (+1)] <*> [1, 2, 3]
[1,4,9,2,3,4]

So, what does "reversed" mean?


Side note: there are applicative functors which have (<**>) = flip (<*>). For example, here is my proof for the reader ((->) e):

(->) e: f <**> g =
    = liftA2 (flip ($)) f g =
    = (flip ($) <$> f) <*> g =
    = \e -> ((flip ($) . f) e) (g e) =
    = \e -> flip ($) (f e) $ (g e) =
    = \e -> (g e) $ (f e) =
    = \e -> g e (f e) =
    = g <*> f. => (<**>) = flip (<*>).


Solution

  • I recently added do-notation to the base documentation which makes it easier to compare <*> and <**>, notice how both of them run left-to-right and both of them return f a:

      fs <*> as
    =
      do f <- fs
         a <- as
         pure (f a)
    

    and

      as <**> fs
    =
      do a <- as
         f <- fs
         pure (f a)
    

    It is known and codified (Control.Applicative.Backwards) that applicatives can be run backwards , I have to cut this answer short. Li-yao Xia's answer with liftA2 ($) and liftA2 (&)