我有功能
doubleMe :: Num a => [a] -> [a]
doubleMe [] = []
doubleMe (x:xs) = (2*x):(doubleMe xs)
考虑一下:
doubleMe(doubleMe([1,2,3]))
第一步显然是
doubleMe(doubleMe([1,2,3])) = doubleMe(2:doubleMe[2,3])
因为没有其他可能性。
这是我想知道的下一步。为什么
doubleMe(2:doubleMe[2,3]) = 4:(doubleMe(doubleMe([2,3])))
而不是
doubleMe(2:doubleMe[2,3]) = doubleMe(2:4:doubleMe([3]))
到目前为止我唯一能够提出的答案是
因为它有意义。否则哈斯克尔就不会在名单上懒散地行动。
但这不是一个答案,而是一个拼写。什么是真正的答案?
答案 0 :(得分:7)
第一步显然是
doubleMe(doubleMe([1,2,3])) = doubleMe(2:doubleMe[2,3])
实际上不是显然!
为了区分,
doubleMe' = doubleMe
并考虑
doubleMe' $ doubleMe [1,2,3]
第一步如你所说的唯一原因,即
≡ doubleMe' $ 2 : doubleMe [2,3]
是因为doubleMe'
需要能够将其参数与[]
或_:_
相匹配。为此,运行时开始评估doubleMe [1,2,3]
一点,即一个递归步骤。这会产生2 : doubleMe [2,3]
,足以让doubleMe'
使用:
≡ 4 : doubleMe' (doubleMe [2,3])
请注意,实际上这个评估顺序不是必需语言:编译器可以重新排序(例如出于性能原因),所以实际上内部列表会立即完全处理 - < strong> if 它可以证明这不会改变语义,即对于无限列表,doubleMe [1..]
如果只询问前几个结果,则不能卡在永恒循环中。
GHC不进行此类重新排序。
答案 1 :(得分:3)
要认识到的重要一点是,case
只有case
导致Haskell [1]中的评估。因此,当你说&#34;考虑一下:&#34;
doubleMe(doubleMe([1,2,3]))
说出我们正在考虑的是至关重要的。在Haskell [1]中,评估不会发生功能应用的副作用。导致(部分)评估它的唯一因素是case
语句,模式匹配它。那么case
如何在这里工作?
好
case doubleMe (doubleMe [1,2,3]) of
[] -> ...
x : xs -> ... x ... xs ...
如下进行。我们必须在函数调用的返回值上进行模式匹配,所以我们用它的body替换函数调用(desugaring函数参数模式匹配到case
)
case (case doubleMe [1,2,3] of
[] -> []
x:xs -> (2*x) : doubleMe xs)
) of
[] -> ...
x : xs -> ... x ... xs ...
我们已经引入了第二个案例,因此会导致评估
case (case (case [1,2,3] of
[] -> []
x:xs -> (2*x) : doubleMe xs
) of
[] -> []
x:xs -> (2*x) : doubleMe xs)
) of
[] -> ...
x : xs -> ... x ... xs ...
现在我们有第三个case
。这个是直接匹配数据结构,因此它立即返回并选择要遵循的适当分支(:
)绑定x
到1
和xs
到{{ 1}}。
[2,3]
现在已对第二个case (case ((2*1) : doubleMe [2,3]
) of
[] -> []
x:xs -> (2*x) : doubleMe xs)
) of
[] -> ...
x : xs -> ... x ... xs ...
的详细信息进行了评估,以便它可以继续选择适当的分支(同样是case
)绑定:
到x
和{{ 1}}到(2*1)
。
xs
最后原始doubleMe [2,3]
可以选择其分支
case ((2*(2*1)) : doubleMe (doubleMe [2,3]))
) of
[] -> ...
x : xs -> ... x ... xs ...
下一个问题是如何评估case
和... (2*(2*1)) ... doubleMe (doubleMe [2,3])) ...
字词。答案是,只有在更高级别(2*(2*1))
审查他们所属的表达方式时才能强迫他们使用。
[1]或者更确切地说是Haskell的 implementation 。原则上Haskell可以以不同的方式实现,但我所知道的所有版本都是这样的。