为什么将此递归映射函数仅应用于列表中的最后两个元素?

aqu*_*an9 2 haskell list lazy-evaluation lazy-sequences map-function

这是给出的问题:下表中的前8个元素是什么?

mystery = 0 : 10 : (map(+1)mystery)
Run Code Online (Sandbox Code Playgroud)

答案是 [0,10,1,11,2,12,3,13...]

但我认为答案应该是[0,10,1,11,1,11,2,12]。以下步骤显示了原因:

1)我们得到了; list,[0,10]因此在第一次应用该函数后,我们有了列表[ 0,10,1, 11] 2)现在有了一个列表[ 0,10,1,11]因此,在再次应用该函数后,结果列表应该是[0,10,1,11,1,11,2,12]

显然不是这样。谁能解释为什么?

che*_*ner 6

在深入探讨的定义之前mystery,让我们看一下要map遵守的法律之一:

map f (map g xs) == map (f . g) xs
Run Code Online (Sandbox Code Playgroud)

此法的非正式证明很容易理解:

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]
Run Code Online (Sandbox Code Playgroud)

考虑到这一点,让我们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
Run Code Online (Sandbox Code Playgroud)

您不是从有限列表开始的[0, 10];您以0和10 开头的无限列表开始,其余元素以递归方式定义。

从某种意义上说,列表没有封闭的形式,但这并不重要。懒惰意味着你只适用mapmystery为需要得到要求的项目。例如,既不head mystery也不是head (tail mystery)永远需要评估的呼吁map,并且head (tail (tail mystery))只需要映射(+1)head mystery,而不是整个无限名单。

懒惰模糊了列表与计算列表的算法之间的区别。