如何解决函数 monad 真的能提供比函数应用函子更多的东西吗?如果是这样,什么?
对于函数 monad,我发现 (<*>)
和 (>>=)
/(=<<)
有两种非常相似的类型。特别是,(=<<)
使相似性更加明显:
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
(=<<) :: (a -> r -> b) -> (r -> a) -> (r -> b)
所以它就像 (<*>)
和 (>>=)
/(=<<)
都取一个二元函数和一个一元函数,并且 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
不能在 (<*>)
、pure
和 fmap
方面实现。
但是我上面提到的 function applicative/mondad 呢?
我知道 join === (>>= id)
以及归结为 \f x -> f x x
的函数 monad,即通过将后者的一个参数作为前者的两个参数提供给二元函数使二元函数成为一元函数。
我可以用(<*>)
来表达吗?好吧,实际上我认为我可以:flip ($) <*> f === join f
是不是正确的? flip ($) <*> f
不是没有 join
/(>>=)
和 (=<<)
的 return
的实现吗?
然而,考虑到列表 applicative/monad,我可以在不显式使用 join
/(=<<)
和 (>>=)
(甚至不使用 return
,fwiw): (<*>)
;因此,实现 join = concat
也可能是一种技巧,并没有真正显示出我是仅依赖于 join f = flip ($) <*> f
还是还依赖于 Applicative
。
解决方法
当您像这样实现 join
时,您使用的函数类型知识超出了 Applicative
所提供的知识。这些知识在 ($)
的使用中被编码。那就是“应用程序”运算符,它甚至是函数的核心。您的列表示例也会发生同样的情况:您使用的是 concat
,它基于对列表性质的了解。
通常,如果您可以使用特定 monad 的知识,则可以表达任何幂的计算。例如,使用 Maybe
,您可以匹配其构造函数并以这种方式表达任何内容。当 LYAH 说 monad 比 applicative 更强大时,它的意思是“作为抽象”,不适用于任何特定的 monad。
edit2: 这个问题的问题在于它含糊不清。它使用了一个根本没有定义的概念(“更强大”),让读者猜测其含义。因此我们只能得到毫无意义的答案。当然,在使用我们可以使用的所有 Haskell 库时,任何东西都可以编码。这是一个空洞的说法。这不是问题。
就我所见,澄清的问题是:分别使用 Monad / Applicative / Functor 中的方法作为 primitives,根本不使用显式模式匹配,是因此,对于使用中的一组或另一组原语,可以严格表达为更大的计算。现在这个可以得到有意义的回答。
虽然函数是不透明的。无论如何都不存在模式匹配。在不限制我们可以使用的情况下,这个问题同样没有意义。然后限制就变成了显式使用命名参数、有针对性的编程风格,因此我们只允许自己以组合风格进行编码。
那么,对于列表,仅使用 fmap
和 app
(<*>
),我们可以表达如此多的计算,并且将 join
添加到我们的武器库确实可以那个更大。函数不是这样。 join = W = CSI = flip app id
。结束。
实现了app f g x = (f x) (g x) = id (f x) (g x) :: (->) r (a->b) -> (->) r a -> (->) r b
,我已经有了flip app id :: (->) r (r->b) -> (->) r b
,我不妨称它为join
,因为类型合适。无论我写与否,它都已经存在。另一方面,从 app fs xs :: [] (a->b) -> [] a -> [] b
,我似乎无法得到 [] ([] b) -> [] b
。 ->
中的两个 (->) r (a->b)
都是相同;函数是 special。
(顺便说一句,我目前不知道如何在不实际将 app
编码为嗯。使用列表推导式等同于使用 join
;而 concat
不是 concat
的实现,它是 {{1 }}).
join
很简单,所以毫无疑问。
(编辑:好吧,显然还有疑问)。
join
用于函数。而已。这就是函数 Monad 和 Applicative Functor 是相同的意思。 join f = f <*> id
是一个普遍适用的组合子。 (=<<) = (<*>) . flip
不是。那里有一定的混淆,当然,功能。但是那里或任何地方都没有特定的函数操作函数(例如 flip
是一个特定的列表操作函数),因为函数是不透明的。
作为一种特定的数据类型,它可以进行模式匹配。作为一个 Monad,虽然它只知道 concat
和 concat
。 >>=
确实使用模式匹配来完成其工作。 return
没有。
concat
在这里类似于列表的 id
,而不是 id
。它的工作原理正是这意味着被视为 Applicative Functor 或 Monad 的函数是相同的。当然,总的来说 Monad 比 Applicative 更强大,但这不是问题。如果您可以用 []
和 concat
表示列表的 join
,我会说这意味着它们对列表也具有相同的功能。
在 <*>
中,[]
和 (=<<) = (<*>) . flip
对它们应用的函数没有任何作用。所以他们不知道这些函数的内部结构。就像,flip
将碰巧正确计算参数列表的长度,如果该列表是例如(.)
。说this,建立在this之上,是使用函数foo = foldr (\x acc -> x+1) 0
的一些内部知识(与[1,2]
相同,使用通过模式匹配了解其参数列表的内部知识)。但仅使用 foo
和 concat
等基本组合符不是。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。