简体   繁体   English

为什么 <$> 是左结合的?

[英]Why is <$> left associative?

fmap is also <$> because it is function application ( $ ) in the functor category. fmap也是<$>因为它是函子类别中的函数应用程序( $ )。

(+5)  $  (*10)  $  10      -- 105
(+5) <$> (*10) <$> [1,2,3] -- [15,25,35]

Then I thought, well in that case <*> is function application in the applicative functor category, and this should work:然后我想,在那种情况下<*>是 applicative functor 类别中的函数应用程序,这应该可以工作:

[(+5), (+10)] <*>  [(*10), (*100)] <*> [1,2,3]  -- ERROR
-- however:
[(+5), (+10)] <*> ([(*10), (*100)] <*> [1,2,3]) -- [15,25,35,...]

So, <$> only works out because fmap for functions happens to be postcomposition, so (+5) <$> (*10) becomes (+5) . (*10)所以, <$>之所以有效,是因为函数的fmap恰好是后组合,所以(+5) <$> (*10)变成(+5) . (*10) (+5) . (*10) which is then applied to [1,2,3] . (+5) . (*10)然后应用于[1,2,3]

However left associativity for all the application operators ( <<= included) seems to me like a poor design choice, especially after they recognized the similarity to $ which is already right-associative.然而,所有应用程序运算符(包括<<= )的左结合在我看来是一个糟糕的设计选择,尤其是在他们认识到与$的相似性之后,这已经是右结合了。 Is there another reason for this?还有其他原因吗?

Really, the reason is probably just that it allows <$> and <*> to share one precedence level.真的,原因可能只是它允许<$><*>共享一个优先级。 We definitely want <*> to be left-associative so stuff like我们肯定希望<*>是左关联的,比如

Prelude> foldr <$> [(+),(*)] <*> [0,1] <*> [[1,2,3], [4,5,6]]
[6,15,7,16,0,0,6,120]

works, and this also makes <$> behave the correct way even though it doesn't have higher precedence.有效,这也使<$>以正确的方式运行,即使它没有更高的优先级。 Actually chaining multiple <$> operators is indeed not very useful with left-associativity.实际上链接多个<$>运算符对于左结合确实不是很有用。

However, it would also not be very useful with right-associativity .但是,它对于右结合也不是很有用 As chepner commented, it's actually a bit funny that $ is right-associative.正如 chepner 评论的那样, $是右结合的实际上有点有趣。 Sure, that allows writing compositions like当然,这允许编写像

Prelude> sum $ map (+3) $ take 19 $ cycle [4..7]
160

but then, this could just as well be written as the arguably more elegant但是,这也可以像可以说更优雅的那样写

Prelude> sum . map (+3) . take 19 . cycle $ [4..7]
160

(more elegant I say, because here the computation-chain is parsed as a single functional pipeline, rather than imperative-style “do this, then that, then...”). (我说得更优雅,因为这里的计算链被解析为一个单一的功能管道,而不是命令式的“做这个,然后那个,然后……”)。 Thanks to the functor laws, this can be done just the same way with <$> and .由于函子定律,这可以通过<$>. as with $ and .$. . .

The only reason why you might prefer the multiple- $ style is that it allows infix expressions in the pipeline, perhaps the most common example being lens updates (which are typically written with the flipped & , but the principle is the same):您可能更喜欢 multiple- $样式的唯一原因是它允许在管道中使用中缀表达式,也许最常见的例子是镜头更新(通常用翻转的&编写,但原理是相同的):

Prelude Control.Lens> [4..7] & ix 1+~9 & ix 2*~8
[4,14,48,7]

This works because $ and & have very low precedence, pretty much lower than any infix operator.这是有效的,因为$&优先级非常低,几乎低于任何中缀运算符。 That's not the case for <$> so you can't do <$>不是这种情况,所以你不能这样做

Prelude Control.Lens> ix 1+~9 <$> [[4..8], [5..9]]

<interactive>:23:1: error:
    Precedence parsing error
        cannot mix ‘+~’ [infixr 4] and ‘<$>’ [infixl 4] in the same infix expression

In such a case, you need to use some parentheses anyway, and then you might as well do it with the also low-precedence composition operators from Control.Category :在这种情况下,您无论如何都需要使用一些括号,然后您也可以使用Control.Category低优先级组合运算符来做到这一点:

Prelude Control.Lens Control.Category> (ix 1+~9 >>> ix 2*~8) <$> [[4..8], [5..9]]
[[4,14,48,7,8],[5,15,56,8,9]]

or with parens around each updater:或者在每个更新程序周围使用括号:

Prelude Control.Lens> (ix 1+~9) . (ix 2*~8) <$> [[4..8], [5..9]]
[[4,14,48,7,8],[5,15,56,8,9]]

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

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