从一个很棒的网站阅读了关于高阶函数的页面后,我仍然无法理解与函数组合配对的否定函数。
更具体地说,请看这段代码:
ghci> map (negate . sum . tail) [[1..5],[3..6],[1..7]]
产生:
[-14,-15,-27]
我再次重新阅读了该页面,但老实说,我仍然不知道那行代码是如何产生这个答案的,如果有人能引导我完成这个过程,我将非常感激!
从一个很棒的网站阅读了关于高阶函数的页面后,我仍然无法理解与函数组合配对的否定函数。
更具体地说,请看这段代码:
ghci> map (negate . sum . tail) [[1..5],[3..6],[1..7]]
产生:
[-14,-15,-27]
我再次重新阅读了该页面,但老实说,我仍然不知道那行代码是如何产生这个答案的,如果有人能引导我完成这个过程,我将非常感激!
map f [a,b,c] = [f a, f b, f c]
因为map f (x:xs) = f x:map f xs
- 适用f
于列表的每个元素。
所以
map (negate.sum.tail) [[1..5],[3..6],[1..7]]
= [(negate.sum.tail) [1..5], (negate.sum.tail) [3..6], (negate.sum.tail) [1..7]]
现在
(negate . sum . tail) [1..5]
= negate (sum (tail [1,2,3,4,5]))
= negate (sum [2,3,4,5])
= negate 14
= -14
因为(f.g) x = f (g x)
和.
是右结合的,所以(negate.sum.tail) xs = (negate.(sum.tail)) xs
又是negate ((sum.tail) xs) = negate (sum (tail xs))
。
tail
为您提供除列表的第一个元素之外的所有内容:tail (x:xs) = xs
例如tail "Hello" = "ello"
sum
,按照您的预期将它们相加,并且
negate x = -x
.
其他的工作类似,减去每个列表尾部的总和。
为了给 AndrewC 的优秀答案添加不同的视角,我通常会根据函子定律和fmap
. 由于map
可以被认为是fmap
对列表的特化,我们可以map
用更通用的替换fmap
并保持相同的功能:
ghci> fmap (negate . sum . tail) [[1..5],[3..6],[1..7]]
现在我们可以使用代数替换来应用合成函子定律来移动合成发生的位置,然后将每个函数单独映射到列表上:
fmap (f . g) == fmap f . fmap g -- Composition functor law
fmap (negate . sum . tail) $ [[1..5],[3..6],[1..7]]
== fmap negate . fmap (sum . tail) $ [[1..5],[3..6],[1..7]]
== fmap negate . fmap sum . fmap tail $ [[1..5],[3..6],[1..7]]
== fmap negate . fmap sum $ fmap tail [[1..5],[3..6],[1..7]]
== fmap negate . fmap sum $ [tail [1..5],tail [3..6],tail [1..7]] -- As per AndrewC's explanation
== fmap negate . fmap sum $ [[2..5],[4..6],[2..7]]
== fmap negate $ [14, 15, 27]
== [-14, -15, -27]