简体   繁体   English

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

[英]Does the function monad really offer something more than the function applicative functor? If so, what?

For the function monad I find that (<*>) and (>>=) / (=<<) have two strikingly similar types.对于 function monad,我发现(<*>)(>>=) / (=<<)有两种非常相似的类型。 In particular, (=<<) makes the similarity more apparent:特别是, (=<<)使相似性更加明显:

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

So it's like both (<*>) and (>>=) / (=<<) take a binary function and a unary function, and constrain one of the two arguments of the former to be determined from the other one, via the latter.因此,就像(<*>)(>>=) / (=<<)都采用二进制 function 和一元 function,并通过两个 ZDBC11CAA5BDA99F77E6FB4DABD8 中的另一个来约束两个 ZDBC11CAA5BDA99F77E6FB4DABD8 中的一个后者。 After all, we know that for the function applicative/monad,毕竟,我们知道对于 function applicative/monad,

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

And they look so strikingly similar (or symmetric, if you want), that I can't help but think of the question in the title.而且它们看起来非常相似(或对称,如果你愿意的话),我不禁想到标题中的问题。

As regards monads being "more powerful" than applicative functors, in the hardcopy of LYAH's For a Few Monads More chapter , the following is stated:至于 monad 比 applicative functors “更强大”,在LYAH 的For a Few Monads More章节的硬拷贝中,陈述如下:

[…] join cannot be implemented by just using the functions that functors and applicatives provide. […] 仅使用函子和应用程序提供的功能无法实现join

ie join can't be implemented in terms of (<*>) , pure , and fmap .join不能用(<*>)purefmap

But what about the function applicative/mondad I mentioned above?但是我上面提到的function applicative/mondad 呢?

I know that join === (>>= id) , and that for the function monad that boils down to \fx -> fxx , ie a binary function is made unary by feeding the one argument of the latter as both arguments of the former. I know that join === (>>= id) , and that for the function monad that boils down to \fx -> fxx , ie a binary function is made unary by feeding the one argument of the latter as both arguments of the以前的。

Can I express it in terms of (<*>) ?我可以用(<*>)来表达吗? Well, actually I think I can: isn't flip ($) <*> f === join f correct?好吧,实际上我认为我可以: flip ($) <*> f === join f不正确吗? Isn't flip ($) <*> f an implementation of join which does without (>>=) / (=<<) and return ? flip ($) <*> f不是没有(>>=) / (=<<)returnjoin实现吗?

However, thinking about the list applicative/monad, I can express join without explicitly using (=<<) / (>>=) and return (and not even (<*>) , fwiw): join = concat ;但是,考虑到列表 applicative/monad,我可以在不显式使用(=<<) / (>>=)return的情况下表达join (甚至不是(<*>) ,fwiw): join = concat ; so probably also the implementation join f = flip ($) <*> f is kind of a trick that doesn't really show if I'm relying just on Applicative or also on Monad .所以也可能实现join f = flip ($) <*> f是一种技巧,如果我仅依赖ApplicativeMonad ,它并没有真正显示出来。

When you implement join like that, you're using knowledge of the function type beyond what Applicative gives you.当您实现这样的join时,您使用的 function 类型的知识超出了Applicative提供的范围。 This knowledge is encoded in the use of ($) .这种知识在($)的使用中被编码。 That's the "application" operator, which is the core of what a function even is.这就是“应用程序”运算符,它甚至是 function 的核心。 Same thing happens with your list example: you're using concat , which is based on knowledge of the nature of lists.您的列表示例也会发生同样的事情:您正在使用concat ,它基于对列表性质的了解。

In general, if you can use the knowledge of a particular monad, you can express computations of any power.通常,如果您可以使用特定 monad 的知识,则可以表达任何幂的计算。 For example, with Maybe you can just match on its constructors and express anything that way.例如,使用Maybe您可以匹配其构造函数并以这种方式表达任何内容。 When LYAH says that monad is more powerful than applicative, it means "as abstractions", not applied to any particular monad.当 LYAH 说 monad 比 applicative 更强大时,它的意思是“作为抽象”,而不适用于任何特定的 monad。

edit2: The problem with the question is that it is vague.编辑2:问题的问题在于它含糊不清。 It uses a notion ("more powerful") that is not defined at all and leaves the reader guessing as to its meaning.它使用了一个根本没有定义的概念(“更强大”),让读者猜测它的含义。 Thus we can only get meaningless answers.因此,我们只能得到无意义的答案。 Of course anything can be coded while using all arsenal of Haskell at our disposal.当然,任何东西都可以在我们使用 Haskell 的所有武器库时进行编码。 This is a vacuous statement.这是一个空洞的说法。 And it wasn't the question.这不是问题所在。

The cleared-up question, as far as I can see, is: using the methods from Monad / Applicative / Functor respectively as primitives , without using explicit pattern matching at all, is the class of computations that can be thus expressed strictly larger for one or the other set of primitives in use.据我所知,明确的问题是:分别使用 Monad / Applicative / Functor 中的方法作为原语,根本不使用显式模式匹配,是计算的 class,因此可以严格表示为更大或正在使用的另一组原语。 Now this can be meaningfully answered.现在可以有意义地回答这个问题。

Functions are opaque though.但是函数是不透明的。 No pattern matching is present anyway.无论如何都不存在模式匹配。 Without restricting what we can use, again there's no meaning to the question.在不限制我们可以使用的情况下,这个问题再次没有意义。 The restriction then becomes, the explicit use of named arguments, the pointful style of programming, so that we only allow ourselves to code in combinatory style.那么限制就变成了,显式使用命名为 arguments 的编程风格,因此我们只允许自己以组合风格进行编码。

So then, for lists, with fmap and app ( <*> ) only, there's so much computations we can express, and adding join to our arsenal does make that larger.因此,对于仅使用fmapapp ( <*> ) 的列表,我们可以表达的计算量非常多,而将join添加到我们的工具库中确实会使计算量更大。 Not so with functions.函数则不然。 join = W = CSI = flip app id . join = W = CSI = flip app id The end.结束。

Having implemented app fgx = (fx) (gx) = id (fx) (gx):: (->) r (a->b) -> (->) r a -> (->) r b , I already have flip app id:: (->) r (r->b) -> (->) r b , I might as well call it join since the type fits.实现了app fgx = (fx) (gx) = id (fx) (gx):: (->) r (a->b) -> (->) r a -> (->) r b已经有flip app id:: (->) r (r->b) -> (->) r b ,我不妨称之为join ,因为类型适合。 It already exists whether I wrote it or not.不管我写不写,它已经存在了。 On the other hand, from app fs xs:: [] (a->b) -> [] a -> [] b , I can't seem to get [] ([] b) -> [] b .另一方面,从app fs xs:: [] (a->b) -> [] a -> [] b ,我似乎无法得到[] ([] b) -> [] b Both -> s in (->) r (a->b) are the same ; (->) r (a->b)中的两个-> s相同 functions are special .功能特殊

(BTW, I don't see at the moment how to code the lists' app explicitly without actually coding up join as well. Using list comprehensions is equivalent to using concat ; and concat is not implementation of join , it is join ). (顺便说一句,我目前还没有看到如何在不实际编码 up join的情况下明确编码列表的app 。使用列表推导等同于使用concat ;并且concat不是join的实现,它join )。


join f = f <*> id

is simple enough so there's no doubts.很简单,所以毫无疑问。


( edit: well, apparently there were still doubts). 编辑:好吧,显然仍然存在疑问)。

(=<<) = (<*>). flip (=<<) = (<*>). flip for functions. (=<<) = (<*>). flip功能。 that's it.而已。 that's what it means that for functions Monad and Applicative Functor are the same.这就是函数 Monad 和 Applicative Functor 相同的意思。 flip is a generally applicable combinator. flip是一个普遍适用的组合子。 concat isn't. concat不是。 There's a certain conflation there, with functions, sure.那里有一定的混淆,当然,功能。 But there's no specific functions-manipulating function there (like concat is a specific lists-manipulating function), or anywhere, because functions are opaque.但是那里没有特定的函数操作 function (比如concat是一个特定的列表操作函数),或者任何地方,因为函数是不透明的。

Seen as a particular data type, it can be subjected to pattern matching.作为一种特定的数据类型,它可以进行模式匹配。 As a Monad though it only knows about >>= and return .作为 Monad 虽然它只知道>>=return concat does use pattern matching to do its work. concat确实使用模式匹配来完成它的工作。 id does not. id没有。

id here is akin to lists' [] , not concat .这里的id类似于列表的[] ,而不是concat That it works is precisely what it means that functions seen as Applicative Functor or Monad are the same.它的工作原理正是意味着被视为 Applicative Functor 或 Monad 的函数是相同的。 Of course in general Monad has more power than Applicative, but that wasn't the question.当然,一般来说 Monad 比 Applicative 更有力量,但这不是问题所在。 If you could express join for lists with <*> and [] , I'd say it'd mean they have the same power for lists as well.如果您可以用<*>[]表示列表的join ,我会说这意味着它们对列表也具有相同的功能。

In (=<<) = (<*>). flip(=<<) = (<*>). flip (=<<) = (<*>). flip , both flip and (.) do nothing to the functions they get applied to. (=<<) = (<*>). flipflip(.)它们应用的函数没有任何作用。 So they have no knowledge of those functions' internals.所以他们不知道这些函数的内部结构。 Like, foo = foldr (\x acc -> x+1) 0 will happen to correctly calculate the length of the argument list if that list were eg [1,2] .就像, foo = foldr (\x acc -> x+1) 0会碰巧正确计算参数列表的长度,如果该列表是例如[1,2] Saying this , building on this , is using some internal knowledge of the function foo (same as concat using internal knowledge of its argument lists, through pattern matching).这个,建立在这个之上,使用 function foo的一些内部知识(与concat使用其参数列表的内部知识相同,通过模式匹配)。 But just using basic combinators like flip and (.) etc., isn't.但仅仅使用基本的组合器,如flip(.)等,不是。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM