Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

<**> 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 (<*>).

like image 652
Zhiltsoff Igor Avatar asked Jul 31 '20 11:07

Zhiltsoff Igor


People also ask

What does reversed () do in Python?

Python reversed() The reversed() method computes the reverse of a given sequence object and returns it in the form of a list.

What is the difference between reverse and reversed?

foo. reverse() actually reverses the elements in the container. reversed() doesn't actually reverse anything, it merely returns an object that can be used to iterate over the container's elements in reverse order. If that's what you need, it's often faster than actually reversing the elements.

What is reversed method?

The reverse method transposes the elements of the calling array object in place, mutating the array, and returning a reference to the array. reverse is intentionally generic; this method can be called or applied to objects resembling arrays.

What does reverse in C++ do?

std::reverse() in C++ reverse() is a predefined function in header file algorithm. It is defined as a template in the above mentioned header file. It reverses the order of the elements in the range [first, last) of any container.


3 Answers

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 (&)

like image 162
Iceland_jack Avatar answered Oct 22 '22 19:10

Iceland_jack


One way to illustrate it symbolically is to compare their expressions in terms of liftA2:

(<*>)  = liftA2 (\f x -> f x)
(<**>) = liftA2 (\x f -> f x)
       = liftA2 (flip (\f x -> f x))
like image 20
Li-yao Xia Avatar answered Oct 22 '22 19:10

Li-yao Xia


If we stay at the example of lists we can see through your examples how <**> behaves reverse.

The expression as <**> fs means something like

foreach a in as {
    foreach f in fs {
        add (f a) to result;
    }
}

and fs <*> as means something like

foreach f in fs {
    foreach a in as {
        add (f a) to result
    }
}

So as <**> fs results in [f1(a1), f2(a1), ..., fn(a1), f1(a2), ..., fn(a2), ...]

And fs <*> as result in [f1(a1), f1(a2), ... , f1(am), f2(a1), ...]

So the order of the loops is reversed.

like image 7
Ackdari Avatar answered Oct 22 '22 18:10

Ackdari