我现在正在学习Haskell并且我读了一本名为“使用Haskell进行功能性思考”的书,我无法理解为什么第一章的表达式为真:
总结。 map sum = sum。的concat
答案 0 :(得分:5)
非正式地说,这只是说因为如果添加是关联的,那么对你添加的数字进行分组并不重要。 (a + b) + (c + d)
与(a + b + c + d)
相同。
在形式上,我们可以使用等式推理和结构归纳来证明任何大小的列表。 (有关这两个过程的快速定义,请参阅最后的内容。)
假设map
,concat
,sum
和(.)
的以下定义:
map sum [] = []
map sum (a:as) = sum a : map sum as
concat [] = []
concat (a:as) = a ++ concat as
sum [] = 0
sum (a:as) = a + sum as
(f . g) x = f (g x)
为了使证明更简单,我们会在没有明确证据的情况下声明(但请参阅下文)
sum (a ++ b) == sum a + sum b
首先,我们确定空列表的标识是真的。
(sum . map sum) [] == sum (map sum []) -- (7)
== sum [] -- (1)
== sum (concat []) -- (3)
== (sum . concat) [] -- (7)
(请注意,我们不需要定义5,因为空列表是空列表。)
现在,为大小为as
的任何列表k
添加新定义。
(sum . map sum) as == (sum . concat) as
如果(9)为真,我们可以证明大小为k+1
的列表的身份:
(sum . map sum) (a:as) == sum (map sum (a:as)) -- (7)
== sum (sum a : map sum as) -- (2)
== sum a + sum (map sum as) -- (6)
== sum a + (sum . map sum) as -- (7)
== sum a + (sum . concat) as -- (9)
== sum a + sum (concat as) -- (7)
== sum (a ++ concat as) -- (8)
== sum (concat (a:as)) -- (4)
== (sum . concat) (a:as) -- (7)
通过归纳,我们已经为任何大小的列表证明了sum . map sum == sum . concat
。
等式推理意味着我们可以使用a = b
这样的平等来将a
替换为b
或b
替换为a
我们的证明。
列表上的结构感应是一个自举过程。您假设某些属性适用于大小为k
的列表,然后使用它来证明大小为k+1
的列表是正确的。然后,如果你能证明k=0
是真的,那么这意味着所有k
都是如此。例如,如果k=0
为真,则k=1
为真,这意味着k=2
等等。
定义4假设++
:
[] ++ bs = bs
(a:as) ++ bs = a : (as ++ bs)
定义++
后,我们可以证明(8):
基本案例:a为空
sum ([] ++ b) == sum b -- definition of ++
== 0 + sum b -- definition of +
== sum [] + sum b -- definition of sum
假设sum (a++b)
的{{1}}长度为a
,
k
答案 1 :(得分:1)
想象一下,我们有一个清单:
myList :: [[Int]]
myList = [[1,2],[3,4,5]]
让我们申请sum . map sum
:
(sum . map sum) [[1,2],[3,4,5]]
= sum [sum [1,2], sum [3,4,5]]
= sum [1+2,3+4+5]
= 1+2+3+4+5
现在让我们应用sum . concat
:
(sum . concat) [[1,2],[3,4,5]]
= sum [1,2,3,4,5]
= 1+2+3+4+5
希望你现在可以看到,因为(a + b)+ c = a +(b + c),我们添加东西的顺序无关紧要,因此对内部列表求和,然后对整个列表求和产生与简单地对内部列表的每个值求和相同的结果。