在阅读an awesome site的高阶函数页面后,我仍然无法理解与函数组合配对的否定函数。
更具体一点,拿这段代码:
ghci> map (negate . sum . tail) [[1..5],[3..6],[1..7]]
产生:
[-14,-15,-27]
我再次重新阅读该页面,但说实话,我仍然不知道这行代码是如何产生这个答案的,如果有人能指导我完成这个过程,我会非常感激!
答案 0 :(得分:15)
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
。
其他人的工作方式类似,减去每个列表尾部的总和。
答案 1 :(得分:5)
为了给AndrewC的优秀答案添加不同的视角,我通常会根据functor laws和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]