【问题标题】:<**> is a variant of <*> with the arguments reversed. What does "reversed" mean?<**> 是 <*> 的变体,参数颠倒了。 “颠倒”是什么意思?
【发布时间】:2020-11-21 05:38:05
【问题描述】:

In GHC.Base the description of &lt;**&gt; runs:

&lt;*&gt; 的变体,参数颠倒。

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

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

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


旁注:有应用函子有(&lt;**&gt;) = flip (&lt;*&gt;)。例如,这是我给读者 ((-&gt;) 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 (<*>).

【问题讨论】:

  • 旁注:(&lt;**&gt;) = flip (&lt;*&gt;) 这样的函子被称为可交换应用函子(或可交换单子,如果它们恰好也是单子)。
  • 可能更好的描述可能是“&lt;*&gt; 的变体,参数的角色颠倒了。”
  • @WillNess 同意了。说实话,我会进一步写下&lt;*&gt; 和&lt;**&gt; 之间的某种关系,例如:xf &lt;**&gt; ff = (&amp;) &lt;$&gt; xf &lt;*&gt; ff。它还会为定义增加更多的间隙,因为右手 IS 定义,只是就&lt;*&gt;,而不是liftA2:liftA2 f xf yf = f &lt;$&gt; xf &lt;*&gt; yf。
  • 有些像liftA2 更好; (&lt;*&gt;) = liftA2 ($) 和 (&lt;**&gt;) = liftA2 (&amp;) 非常漂亮和清晰。和短。 :)

标签: haskell operators terminology applicative


【解决方案1】:

我最近添加了do-notation to the base documentation,这使得比较&lt;*&gt; 和&lt;**&gt; 变得更容易,注意它们是如何从左到右运行并且它们都返回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 (&) 回答

【讨论】:

    【解决方案2】:

    象征性地说明它的一种方法是比较它们在liftA2方面的表达:

    (<*>)  = liftA2 (\f x -> f x)
    (<**>) = liftA2 (\x f -> f x)
           = liftA2 (flip (\f x -> f x))
    

    【讨论】:

    • 我想这就是我用来为读者证明&lt;**&gt;和flip (&lt;*&gt;)等价的东西。
    • 也许使用($)?
    • @dfeuer 好吧,据我所知,$ 不能用于Control.Applicative。我想我们是否想在图书馆之外遵循这条规则取决于我们。
    • @ZhiltsoffIgor,这是在开玩笑吗?在GHC.Base 中使用($) 可能(我不知道)会出现问题,但我无法想象这是其他地方的问题。
    • @dfeuer 来自 Control.Applicative:>注意:请勿在此模块中的任何位置使用 ($)! ($) 的类型有点神奇(它可以返回未提升的类型),并且它是连线的……如果您点击我在第一行中附上我的问题的链接,您可以查看全文(第一个注释在模块)。作者再次警告我们不要在&lt;**&gt; 的定义下使用$。
    【解决方案3】:

    如果我们停留在列表的示例中,我们可以通过您的示例看到 &lt;**&gt; 的行为是反向的。

    表达式as &lt;**&gt; fs 的意思类似于

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

    而fs &lt;*&gt; as 表示类似

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

    所以as &lt;**&gt; fs 的结果是[f1(a1), f2(a1), ..., fn(a1), f1(a2), ..., fn(a2), ...]

    而fs &lt;*&gt; as 导致[f1(a1), f1(a2), ... , f1(am), f2(a1), ...]

    所以循环的顺序是颠倒的。

    【讨论】:

    • 是的!函子是广义循环[ f x | x &lt;- xs];应用程序是广义的嵌套循环[ (x,y) | x &lt;- xs, y &lt;- ys]; Monad 是广义的动态创建 嵌套循环[ (x,y) | x &lt;- xs, y &lt;- k x].
    • 或者我们可以选择另一个基地,fmap f xs = [ f x | x &lt;- xs]、ap xs ys = [ x y | x &lt;- xs, y &lt;- ys]、join xs = [ y | x &lt;- xs, y &lt;- x]。当然,所有这些都是用 MonadComprehensions 编写的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-11
    • 1970-01-01
    • 1970-01-01
    • 2021-12-30
    相关资源
    最近更新 更多