函数单子真的提供了比函数应用函子更多的东西吗?如果是这样,是啥?

Posted

技术标签:

【中文标题】函数单子真的提供了比函数应用函子更多的东西吗?如果是这样,是啥?【英文标题】:Does the function monad really offer something more than the function applicative functor? If so, what?函数单子真的提供了比函数应用函子更多的东西吗?如果是这样,是什么? 【发布时间】:2021-08-19 02:51:50 【问题描述】:

对于函数 monad,我发现 (<*>)(>>=)/(=<<) 有两个非常相似的类型。特别是,(=<<) 使相似性更加明显:

(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
(=<<) :: (a -> r -> b) -> (r -> a) -> (r -> b)

所以就像(&lt;*&gt;)(&gt;&gt;=)/(=&lt;&lt;) 都采用二元函数和一元函数,而constrain 前者的两个参数之一通过后者从另一个参数中确定.毕竟,我们知道对于函数 applicative/monad,

f <*> g = \x -> f x (g x)
f =<< g = \x -> f (g x) x 

而且它们看起来非常相似(或者对称,如果你愿意的话),我不禁想到标题中的问题。

关于 monad 比应用函子“更强大”,在LYAH's For a Few Monads More chapter 的硬拷贝中,声明如下:

[…] join 不能仅通过函子和应用程序提供的函数来实现。

join不能在(&lt;*&gt;)purefmap方面实现。

但是我上面提到的 function applicative/mondad 呢?

我知道 join === (&gt;&gt;= id),对于归结为 \f x -&gt; f x x 的函数 monad,即通过将后者的一个参数作为前者的两个参数提供二元函数而成为一元函数。

我可以用(&lt;*&gt;) 来表达吗?好吧,实际上我认为我可以:flip ($) &lt;*&gt; f === join f 不正确吗? flip ($) &lt;*&gt; f 不是没有 (&gt;&gt;=)/(=&lt;&lt;)returnjoin 的实现吗?

但是,考虑到列表 applicative/monad,我可以在不明确使用 (=&lt;&lt;)/(&gt;&gt;=)return 的情况下表达 join(甚至不能使用 (&lt;*&gt;),fwiw):join = concat;所以可能join f = flip ($) &lt;*&gt; f 的实现也是一种技巧,如果我仅依赖ApplicativeMonad,它并没有真正显示出来。

【问题讨论】:

评论不用于扩展讨论;这个对话是moved to chat。 【参考方案1】:

当你像这样实现join 时,你使用的函数类型知识超出了Applicative 给你的范围。这些知识在($) 的使用中被编码。那就是“应用程序”运算符,它甚至是函数的核心。您的列表示例也会发生同样的情况:您使用的是 concat,它基于对列表性质的了解。

一般来说,如果你可以使用特定单子的知识,你就可以表达任何幂的计算。例如,使用Maybe,您可以匹配其构造函数并以这种方式表达任何内容。当 LYAH 说 monad 比 applicative 更强大时,它的意思是“作为抽象”,不应用于任何特定的 monad。

【讨论】:

Fyodor,你会说函数类型的知识在 Will Ness 的回答中编码在哪里? @Enlico id 是一个函数。 (&lt;*&gt; id) 不是可以与任何应用程序一起使用的多态函数。同样,只有函数(&gt;&gt;= id)(id &gt;&gt;=)是一样的。 @Bergi id 这里类似于列表的[],而不是concat。它的工作原理正是函数应用程序的含义。和星期一。有同样的权力。否则,我们在说什么,一般来说 Monad 比 App 更强大?当然有,但这不是问题。如果你可以用&lt;*&gt;[] 表示join,我会说这意味着它们在那里也有同样的力量。 “一般来说,如果你可以使用特定 monad 的知识”,您的意思是“特定数据类型”。就像您建议使用模式匹配一​​样。 Monad 上没有模式匹配作为 Monad,只有数据类型。作为 Monad,它只知道 &gt;&gt;=return @WillNess 他是说 particular monad,functions,拥有函数的全部力量。这个特殊的应用程序也是如此。【参考方案2】:

edit2: 这个问题的问题在于它含糊不清。它使用了一个根本没有定义的概念(“更强大”),让读者猜测它的含义。因此,我们只能得到无意义的答案。当然,任何东西都可以在使用我们可以使用的所有 Haskell 库时进行编码。这是一个空洞的说法。这不是问题。

据我所知,明确的问题是:使用 Monad / Applicative / Functor 中的方法分别作为 primitives,根本不使用显式模式匹配,是因此,对于使用中的一组原语或另一组原语,可以严格表示为更大的计算。现在这个可以得到有意义的回答了。

函数是不透明的。无论如何都不存在模式匹配。在不限制我们可以使用的情况下,这个问题再次没有意义。然后限制就变成了,显式使用命名参数,编程的重点风格,所以我们只允许自己以组合风格编码。

那么,对于列表,只有fmapapp (&lt;*&gt;),我们可以表达很多计算,而将join 添加到我们的工具库中确实会变得更大。函数则不然。 join = W = CSI = flip app id。结束。

实现了app f g x = (f x) (g x) = id (f x) (g x) :: (-&gt;) r (a-&gt;b) -&gt; (-&gt;) r a -&gt; (-&gt;) r b,我已经有了flip app id :: (-&gt;) r (r-&gt;b) -&gt; (-&gt;) r b,我不妨称它为join,因为类型适合。不管我写不写,它已经存在了。另一方面,从app fs xs :: [] (a-&gt;b) -&gt; [] a -&gt; [] b,我似乎无法得到[] ([] b) -&gt; [] b(-&gt;) r (a-&gt;b) 中的两个-&gt;s 是相同;函数 special.

(顺便说一句,我目前不知道如何编码列表的app 显式而不实际编码join。使用列表理解等同于使用concat;而concat 不是 join 的实现,它 join)。


join f = f <*> id

很简单,所以毫无疑问。


edit:好吧,显然还有疑问)。

(=&lt;&lt;) = (&lt;*&gt;) . flip 用于函数。而已。这就是函数 Monad 和 Applicative Functor 相同的意思。 flip 是一个普遍适用的组合子。 concat 不是。那里有一定的混淆,当然,功能。但是那里没有特定的函数操作函数(比如concat 是一个特定的列表操作函数)或任何地方,因为函数是不透明的。

作为一种特殊的数据类型,它可以进行模式匹配。作为一个 Monad 虽然它只知道&gt;&gt;=returnconcat 确实使用模式匹配来完成它的工作。 id 没有。

id 这里类似于列表的[],而不是concat。它的工作原理正是意味着被视为 Applicative Functor 或 Monad 的函数是相同的。当然,一般来说 Monad 比 Applicative 更有力量,但这不是问题所在。如果您可以用&lt;*&gt;[] 为列表表达join,我会说这意味着它们对列表也具有相同的功能。

(=&lt;&lt;) = (&lt;*&gt;) . flip 中,flip(.) 对它们所应用的函数都不执行任何操作。所以他们不知道这些函数的内部结构。就像,foo = foldr (\x acc -&gt; x+1) 0 会碰巧正确计算参数列表的长度,如果该列表是例如[1,2]。说 this,建立在 this 之上,is 使用函数 foo 的一些内部知识(与 concat 使用其内部知识相同)参数列表,通过模式匹配)。但仅使用 flip(.) 等基本组合符是不行的。

【讨论】:

我开始明白你的意思了,威尔。我还添加了组合逻辑标签,因为它与您的回答最相关。 我不明白。 idflip 都特定于函数,而不是 Applicative 接口的一部分。 (好吧,id 实际上适用于一般的Categorys,但它仍然不是Applicative 的一部分。) @WillNess 正如您已经提到的(如果我理解正确的话)函数具有双重作用:被视为一种数据类型,它们形成一个单子。但它们也是为所有实例编码 monad 操作的方法。然而,正如我现在所看到的,不能从这种二元性中推断出函数类型本身是特殊的。 flip 可能比concat 更具多态性,但它仍然使用函数箭头-&gt; 的知识。 concat 使用模式匹配作为[] 的排除规则。但是flip使用函数应用作为-&gt;的排除规则。这有意义吗? 啊,现在我可以看到了。 flip 这里被视为curry . (. swap) . uncurry? @dfeuer 或者您可能在强调 Hask 是 CCC 并且函数既是其态射又是指数的事实。 (我这么说的问题是我个人几乎不明白我在那里使用的单词,这就是为什么我没有在答案中说出来)

以上是关于函数单子真的提供了比函数应用函子更多的东西吗?如果是这样,是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Swift函数式编程十三(函子适用函子单子)

Swift函数式编程十三(函子适用函子单子)

高阶函数式编程:在 Kotlin 中“实现”单子(Monad)

范畴论-一个单子(Monad)说白了不过就是自函子范畴上的一个幺半群而已

进阶学习4:函数式编程FP——函子FunctorMayBe函子Either函子IO函子FolktalePointer函子Monad

Haskell 中的单子——洪峰老师讲创客道(三十五)