函数 monad 真的提供比函数应用函子更多的东西吗?如果是这样,怎么办



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

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

因此,就像(<*>)(>>=)/(=<<)都采用二进制函数和一元函数,并通过后者将前者的两个参数中的一个限制为从另一个参数确定。毕竟,我们知道对于函数应用/monad,

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

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

关于monad比应用函子"更强大",在LYAH的">For a Few monads More"一章的硬拷贝中,陈述如下:

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

join不能在(<*>)purefmap方面实现。

但是我上面提到的功能应用/mondad呢?

我知道join === (>>= id),并且对于归结为f x -> f x x的函数monad,即通过将后者的一个参数作为前者的两个参数来提供二进制函数

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

但是,考虑到列表 applicative/monad,我可以表达join而无需明确使用(=<<)/(>>=)return(甚至不是(<*>),fwiw):join = concat; 所以可能实现join f = flip ($) <*> f也是一种技巧,并没有真正显示我是否只依赖Applicative或也依赖于Monad

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

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

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

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

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

因此,对于列表,只有fmapapp(<*>),我们可以表达很多计算,并且将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)中的两个->相同的;功能特殊。

(顺便说一句,我目前看不到如何在不实际编码join的情况下显式编码列表的app。使用列表推导等效于使用concat;concat不是join的实现,而是join)。

<小时 />
join f = f <*> id

很简单,所以毫无疑问。


(编辑:好吧,显然仍然存在疑问)。

(=<<) = (<*>) . flip函数。就是这样。这就是函数 Monad 和 Applicative 函子是相同的。flip是一个普遍适用的组合器。concat不是。当然,那里有一定的融合,与函数。但是那里没有特定的函数操作函数(就像concat是一个特定的列表操作函数),或者任何地方,因为函数是不透明的。

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

id这里类似于列表的[],而不是concat。它的工作原理正是它的意思,即被视为应用函子或 Monad 的函数是相同的。当然,一般来说,Monad比Applicative拥有更大的权力,但这不是问题所在。如果你能表达对<*>[]列表的join,我会说这意味着它们对列表也有相同的权力。

(=<<) = (<*>) . flip中,flip(.)对它们所应用的函数没有任何作用。因此,他们不了解这些函数的内部结构。就像,如果参数列表是例如,foo = foldr (x acc -> x+1) 0将碰巧正确计算参数列表的长度[1,2].以此为基础,这样说是使用函数foo的一些内部知识(与concat通过模式匹配使用其参数列表的内部知识相同)。但仅仅使用基本的组合器,如flip(.)等,不是。

相关内容

最新更新