这是给出的问题:下表中的前8个元素是什么?
mystery = 0 : 10 : (map(+1)mystery)
答案是[0,10,1,11,2,12,3,13...]
但是我认为答案应该是[0,10,1,11,1,11,2,12]
。以下步骤说明了原因:
1)我们得到了;列表[0,10]
,因此在第一次应用该函数后,我们有了列表[0,10,1, 11]
2)现在我们有了列表[0,10,1,11]
,因此再次应用该函数后,结果列表应为[0,10,1,11,1,11,2,12]
显然不是这样。谁能解释为什么?
答案 0 :(得分:6)
在深入探讨mystery
的定义之前,让我们看一下map
遵守的定律之一:
map f (map g xs) == map (f . g) xs
此法的非正式证明很容易遵循:
map f (map g [x1, x2, ..., xn]) == map f [g x1, g x2, ..., g xn]
== [f (g x1), f (g x2), ..., f (g xn)]
== [(f.g) x1, (f.g) x2, ..., (f.g) xn]
== map (f.g) [x1, x2, ..., xn]
考虑到这一点,让我们逐步扩展mystery
:
mystery == 0 : 10 : map (+1) mystery
-- by definition of mystery
== 0 : 10 : map (+1) (0 : 10 : map (+1) mystery)
-- by definition of map and the fact that 0 + 1 == 1
== 0 : 10 : 1 : map (+1) (10 : map (+1) mystery)
-- by definition of map and the fact that 10 + 1 == 11
== 0 : 10 : 1 : 11 : map (+1) (map (+1) mystery)
-- using the law above, and the fact that (+1) . (+1) == (+2)
== 0 : 10 : 1 : 11 : map (+2) mystery
== 0 : 10 : 1 : 11 : map (+2) (0 : 10 : map (+1) mystery)
== 0 : 10 : 1 : 11 : 2 : map (+2) (10 : map (+1) mystery)
== 0 : 10 : 1 : 11 : 2 : 12 : map (+2) (map (+1) mystery)
== 0 : 10 : 1 : 11 : 2 : 12 : map (+3) mystery
-- etc
您不是从有限列表[0, 10]
开始;您可以从一个无限列表开始,该列表以0和10开始 ,其余元素以递归方式定义。
从某种意义上说,列表没有封闭的形式,但这没关系;懒惰意味着您仅在需要时将map
应用于mystery
才能获得请求的项目。例如,head mystery
和head (tail mystery)
都不需要评估对map
的呼叫,并且head (tail (tail mystery))
仅需要将(+1)
映射到head mystery
,而不是整个无限列表。
懒惰模糊了列表和计算列表的算法之间的区别。
答案 1 :(得分:4)
让我们使用map
的递归定义来完成它:
map _ [] = []
map f (x:xs) = f x : map f xs
自从我们有了
mystery = 0:10:(map (+1) mystery)
我们已经知道
mystery = [0, 10, ...]
,而...
代表map (+1) mystery
。因此,让我们使用上面的定义进行计算。
我们将其应用于的列表显然不是空的-它以0和10开头。因此,我们使用第二行,其中x
为0,xs
为{{1} }:
10:(map (+1) mystery)
或者,再次将公式用于第一层嵌套:
map (+1) mystery = 1:(map (+1) (10:(map (+1) mystery)))
因此,回到map (+1) mystery = 1:11:(map (+1) (map (+1) mystery))
本身,我们现在知道它的前四个元素:
mystery
,mystery = [0, 10, 1, 11, ...]
代表...
的内容。也就是说,基于以上结果:
map (+1) (map (+1) mystery)
在这里,我将为您保留评估的详细信息,因为现在应该清楚会发生什么情况:前两个元素(在map (+1) (1:11:(map (+1) (map (+1) mystery)))
中将是第5个和第6个元素)将是2和12。其余为mystery
。通过完全相同的过程,它们将从3和13开始。如此一来,就尽您所能进行计算了。
答案 2 :(得分:1)
因为
mystery = 0 : 10 : map (+1) mystery
根据(!!)
和(:)
和map
的定义,情况就是这样
mystery !! 0 = 0 -- pseudocode
mystery !! 1 = 10
mystery !! n | n > 1
= (0 : 10 : map (+1) mystery) !! n
= (10 : map (+1) mystery) !! (n-1)
= (map (1+) mystery) !! (n-2)
= 1 + (mystery !! (n-2))
有您的答案。
说明:
-- 0 1 2 3 4 5 6 -- n
mystery = [0, 10, 1, 11, 2, 12, 3, ...
-- / / / / /
-- 0 1 2 3 4 -- n-2
-- [0, 10, 1, 11, 2, ...
因此,所有元素都是相对于前一个,两个位置优先的元素定义的。
另一种记下同一件事的方法是使配对变得清晰(没有 zipping )
mystery = 0 : 10 : zipWith (+) mystery
(repeat 1)
翻译成命令式伪代码的程序
main = print mystery
实际上与
相同main :
a = 0
b = 10
print "["
while( True ) :
print a ,
print b ,
a += 1
b += 1
解决这些问题的原则方法是命名您的所有临时实体。然后,神秘感消失了:
mystery = 0 : 10 : map (+1) mystery
= x0 : t1
where
x0 = 0
t1 = 10 : map (+1) mystery
= x1 : t2
where
x1 = 10
t2 = map (+1) mystery
= map (+1) (x0 : t1)
= x0+1 : map (1+) t1
= x2 : t3
where
x2 = x0+1 = 0+1 = 1
t3 = map (1+) t1 = map (1+) (x1 : t2)
= x1+1 : map (1+) t2
= x3 : t4
where
....
在简化过程中,除了(1+)
函数之外,我们什么都没有得到,也没有一个以上。
对于xn := 1 + xn-2
以上的所有n
,我们得到的都是1
。