Enr*_*lis 15 monads haskell functional-programming applicative combinatory-logic
对于函数 monad,我发现(<*>)和(>>=)/(=<<)有两个非常相似的类型。特别是,(=<<)使相似性更加明显:
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
(=<<) :: (a -> r -> b) -> (r -> a) -> (r -> b)
Run Code Online (Sandbox Code Playgroud)
所以它就像(<*>)和(>>=)/(=<<)取一个二元函数和一个一元函数,并限制前者的两个参数之一通过后者从另一个参数中确定。毕竟,我们知道对于函数 applicative/monad,
f <*> g = \x -> f x (g x)
f =<< g = \x -> f (g x) x
Run Code Online (Sandbox Code Playgroud)
它们看起来非常相似(或者对称,如果你愿意的话),我不禁想到标题中的问题。
关于 monad 比应用函子“更强大”,在LYAH 的For a few Monads More章节的硬拷贝中,声明如下:
[...]
join不能仅使用函子和应用程序提供的函数来实现。
即join不能在以下方面来实现(<*>),pure和fmap。
但是我上面提到的 applicative/mondad函数呢?
我知道,join === (>>= id)对于归结为 的函数 monad \f x -> f x x,即通过将后者的一个参数作为前者的两个参数提供,使二元函数成为一元函数。
我可以用 来表达(<*>)吗?好吧,实际上我认为我可以:对flip ($) <*> f === join f吗?不是flip ($) <*> f的实现join它确实没有(>>=)/(=<<)和return?
然而,想着列表应用性/单子,我可以表达join不明确使用(=<<)/(>>=)和return(甚至没有(<*>),FWIW)join = concat; 所以可能这个实现join f = flip ($) <*> f也是一种技巧,它并没有真正显示出我是仅仅依赖Applicative还是也依赖Monad.
Fyo*_*kin 22
当你这样实现时join,你使用的函数类型知识超出Applicative了你的知识范围。这些知识在使用中编码($)。那就是“应用程序”运算符,它甚至是函数的核心。同样的事情发生在您的列表示例中:您正在使用concat,这是基于对列表性质的了解。
一般而言,如果您可以使用特定 monad 的知识,则可以表达任何幂的计算。例如,Maybe您可以匹配其构造函数并以这种方式表达任何内容。当 LYAH 说 monad 比 applicative 更强大时,它的意思是“作为抽象”,不适用于任何特定的 monad。
edit2:这个问题的问题在于它含糊不清。它使用了一个根本没有定义的概念(“更强大”),让读者猜测其含义。这样我们只能得到毫无意义的答案。当然,在使用我们可以使用的所有 Haskell 库的同时,任何东西都可以编码。这是一个空洞的说法。这不是问题。
据我所知,已解决的问题是:分别使用 Monad / Applicative / Functor 中的方法作为原语,而不使用显式模式匹配,是一类可以因此严格表达为更大的计算或正在使用的其他原语集。现在这个问题可以得到有意义的回答了。
但函数是不透明的。无论如何都不存在模式匹配。如果不限制我们可以使用的内容,这个问题就没有任何意义。那么限制就变成了显式使用命名参数、有意义的编程风格,这样我们就只允许自己以组合风格进行编码。
那么,对于仅使用fmapand 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。中的两个->s(->) r (a->b)相同;功能比较特殊。
(顺便说一句,我目前不知道如何在不实际编码的情况下显式编码列表。使用列表推导式相当于使用; 并且不是的实现,它是)。app joinconcatconcatjoin join
join f = f <*> id
Run Code Online (Sandbox Code Playgroud)
很简单,所以没有疑问。
(编辑:嗯,显然仍然存在疑问)。
(=<<) = (<*>) . flip对于功能。就是这样。这就是说对于函数 Monad 和 Applicative Functor 来说是相同的。flip是一个普遍适用的组合器。concat不是。当然,这与功能存在一定的混淆。但是那里或任何地方都没有特定的函数操作函数(就像concat特定的列表操作函数一样),因为函数是不透明的。
作为一种特定的数据类型,它可以进行模式匹配。作为一个 Monad,虽然它只知道>>=和return。concat确实使用模式匹配来完成其工作。id才不是。
id这里类似于lists' [],而不是concat. 它的工作原理正是意味着被视为 Applicative Functor 或 Monad 的函数是相同的。当然,一般来说 Monad 比 Applicative 更强大,但这不是问题所在。如果你可以用and来表达join列表,我想说这意味着它们对列表也有相同的能力。<*>[]
在 中(=<<) = (<*>) . flip, 和flip都对它们所应用的函数(.)不执行任何操作。所以他们不了解这些函数的内部结构。就像,如果该列表是例如,将会正确计算参数列表的长度。在此基础上说this,正在使用函数的一些内部知识(与通过模式匹配使用其参数列表的内部知识相同)。但仅使用诸如 等基本组合器则不然。foo = foldr (\x acc -> x+1) 0[1,2]fooconcatflip(.)
| 归档时间: |
|
| 查看次数: |
948 次 |
| 最近记录: |