如果Erlang中的以下代码等同于分配给Four的值,则该代码的值为3;
run() ->
Four = 4,
case 3 of
Four -> io:format("3 == 4~n", []);
_ -> io:format("3 /= 4~n", [])
end.
执行时打印出“3 / = 4”。 Haskell中的类似代码:
main = do
let four = 4
case 3 of
four -> putStrLn "3 == 4"
_ -> putStrLn "3 /= 4"
打印“3 == 4”这是一个声明,我不是(在我生命中的这一点)准备接受为真理。
为什么Haskell不让我匹配以前绑定的变量?它是每个设计还是仅仅是一个do-notation的结果(顺便说一下表达式的情况,我测试了在一个案例中将名称绑定到一个值...然后在另一个案例中匹配它...它没有工作)实施? 有没有办法让它工作,像Erlang一样酷或简单,还是我必须手动比较它们?
答案 0 :(得分:4)
这来自一般的静态范围规则,以及变量的重命名(alpha-conversion)。例如。我们知道
(\x -> x + 1)
与
相同(\y -> y + 1)
在任何情况下。这对其他绑定器的工作方式相同:
let x = 1 in f x -- is the same as
let y = 1 in f y
另外
case e of x -> f x -- is the same as
case e of y -> f y
某些语言,例如Erlang,决定打破这种常规重命名规则,特殊外壳模式匹配外部作用域中定义的变量。 我说大多数功能语言都决定遵循它。
在Haskell中,您可以使用
实现相同目的case e of v | v == previousVariable -> ...
请注意,这需要(==)
,因此Eq
实例必须可用。也就是说,它适用于Int
s,但不适用于函数(或缺少比较器的其他类型)。
答案 1 :(得分:0)
在这种情况下,Haskell不会将four = 4
与3
的值four
作为模式(在这种情况下会抓住所有内容)进行比较因此,->
four
的右侧现在为four == 3
(它会影响上面的绑定)
let four = 4
case 3 of
x | four == x -> putStrLn "3 == 4"
| otherwise -> putStrLn "3 /= 4"
inestead