Haskell在什么程度上懒惰?
我需要一些关于Haskell的懒惰的澄清。
如果我有这个功能:
myFunction arg
| arg == 1 = a
| arg == 2 = a*b
| arg == 3 = b+c
| otherwise = (a+b)*c
where
a = ...
b = ...
c = ...
d = ...
当我调用myFunction 1
,Haskell将只评估a = ...
函数,既不b也不c ,也不d 。
但是,如果我写
myFunction arg
| arg == 1 = a
| arg == 2 = a*b
| arg == 3 = b+c
| otherwise = (a+b)*c
where
(a,b,c,d) = anotherFunction arg
Haskell的行为是什么?
anotherFunction
? anotherFunction
结果吗? 在这两种情况下,除非需要价值,否则它不会评估任何东西。 苛刻的值的一种方法是在调用该ghci中函数(它打印在值ghci
,因此,要求它)。 假设你正在执行该函数,那么在第二种情况下,它将评估元组为弱头标准形式(WHNF),然后评估(a,b,c,d)
的第一个元素,因为只需要该值。 其他元素b
, c
和d
将采用thunk形式。 事实上,你可以验证你自己:
myFunction arg
| arg == 1 = a
| arg == 2 = a*b
| arg == 3 = b+c
| otherwise = (a+b)*c
where
(a,b,c,d) = anotherFunction arg
anotherFunction x = (x, undefined, undefined, undefined)
在ghci中演示:
λ> myFunction 1
1
那么它只对a
兴趣,所以这意味着有一个隐含的函数 :
thea :: (a,b,c,d) -> a
thea (a,_,_,_) = a
换句话说,Haskell对元组的其他元素不感兴趣 。 然而,有时元组的元素共享某种结构。 说另一个功能被定义为:
anotherFunction :: Int -> (Int,Int,Int,Int)
anotherFunction x = (z,t,f,g)
where f = x*x
g = f+x
z = g-2
t = 3
在这种情况下 - 为了评估第一个元素 - 第三个和第四个元素也将被评估。 但是由于你对他们没有做任何事情,Haskell对他们的结果没有特别的兴趣。
正如其他人已经指出的,只有a
将被评估。
不过请记住,为了利用懒惰, anotherFunction
在评估其组件之前返回一个元组是至关重要的。 例如,考虑
anotherFunction n = if p > 1000 then (n, p) else (n, 0)
where p = product [1..n]
即使主叫方只要求第一对分量(即n
),以上将始终评估product [1..n]
。 这是因为if
需要在对可以返回之前进行评估,并且强制p
。 相比之下,
anotherFunction n = (n, if p > 1000 then p else 0)
where p = product [1..n]
将立即退还这一对。 如果只评估其第一个组件,那么根本不会计算p
。