Haskell的惰性求值可以隐藏不必要的运行时错误

今天在做Multiple Variable Declaration Evaluation时遇到了一个解释不通的现象,百思不得其解,最后经多次尝试,发现是Haskell的惰性求值(lazy evaluation)干的好事。

解释不通的代码是这样的:

按照我的预测,当执行evaluate (DeclareMulti [(“x”, (Num 3)), (“x”, (Add (Var “x”) (Num 2)))] (Mult (Var “x”) (Num 2)))时,应该返回error,因为第二个x=x+2中右端的x还没有被加入env(ironment)中,也就无法运算。但是,真正的结果却是6(即3*2),也就是说第二个declaration中的错误并没有影响到整句的执行并输出error。而如果将这个语句做一个小小的改动,变成evaluate (DeclareMulti [(“x”, (Add (Var “x”) (Num 2))), (“x”, (Num 3))] (Mult (Var “x”) (Num 2))),即对调两个declaration的位置,就不能正常得到结果,而是返回了我期望的error。

百思不得其解的我尝试了以下语句:

终于我明白了问题所在——惰性求值。这是haskell的一个语言特性,它会只计算为了得出最终结果而真正需要的部分,其他部分即使代码中看起来让它算了它也不会算。为了计算(Mult (Var “x”) (Num 2)),只需要environment中最前面的x的binding就可以了(因为前面的会shadow后面的,后面的算出来也用不上),所以就只算两个对于”x”的declaration的前面一个,所以将有错的declaration放在后面并不会被执行也不会有error,放在前面就会被执行并且有error。