<**> 是 <*> 的变体,参数相反。 "reversed" 是什么意思?

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

众所周知,这种情况下的“反转”并不意味着“翻转”,因为:

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

那么,“反转”是什么意思?


旁注:有些应用函子具有 (<**>) = flip (<*>)。例如,这是我对 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 (<*>).

一种象征性地说明它的方法是根据 liftA2:

来比较它们的表达式
(<*>)  = liftA2 (\f x -> f x)
(<**>) = liftA2 (\x f -> f x)
       = liftA2 (flip (\f x -> f x))

如果我们停留在列表的示例上,我们可以通过您的示例看到 <**> 的行为如何相反。

表达式 as <**> fs 的意思类似于

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

fs <*> as的意思是

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

所以 as <**> fs 结果是 [f1(a1), f2(a1), ..., fn(a1), f1(a2), ..., fn(a2), ...]

fs <*> as导致[f1(a1), f1(a2), ... , f1(am), f2(a1), ...]

所以循环的顺序是相反的。

我最近添加了 do-notation to the base documentation,这使得比较 <*><**> 变得更容易,请注意它们都是 运行 从左到右,并且它们都是return f a:

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

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

众所周知 codified (Control.Applicative.Backwards) 应用程序可以 运行 向后,我不得不缩短这个答案。 Li-yao Xia 的答案是 liftA2 ($) 和 liftA2 (&)