Haskell中“case”表达式的求值

tquggr8v  于 2022-11-14  发布在  其他
关注(0)|答案(2)|浏览(221)

我目前正在学习 haskell 和碰撞到这个表达式。

statement
   case 1 ´div´ 0 of _ -> 42

我的直觉是,这将导致运行时错误,因为除法为0,但从测试来看,情况并非如此。
我的结论是,这一定是由于Haskell内的懒惰求值。而且,因为_匹配任何东西,它不会检查它与什么比较?
因此,如果有人能告诉我,如果这个评估是正确的,如果不是为什么。也请详细说明什么前提下,一个案件行可以匹配,而不实际上看表达式。

ymdaylpp

ymdaylpp1#

“你的分析很准确,但这实际上是非常精细的。它并不复杂,但它需要仔细考虑非常精确的问题。”
在 haskell
case表达式的一般形式为

case exp0 of {pat1 -> exp1 ; ...}

在计算case表达式时,exp0的计算结果足以确定它是否与pat1匹配。如果匹配,case表达式将使用为它创建的任何附加绑定pat1来计算exp1。如果不匹配,则福尔斯下一个模式或保护并重复。(如果没有匹配,则计算为异常。)
值得注意的是,你的第一个选择匹配所有的东西,而不需要任何求值,所以没有对div 1 0求值,模式不绑定任何东西,然后case表达式求值为42。
这与您执行以下操作的情况不同:

case 1 `div` 0 of
    0 -> 42
    _ -> 42

在这种情况下,必须计算div表达式以查看它是否等于0。这将导致异常,该异常将成为整个case表达式的结果。即使两个分支具有相同的值,也是如此。模式的内容对于确定与严格性相关的行为非常重要。

核心

GHC Haskell编译器是目前最常见的编译器,它有一个称为“core”的中间表示,看起来与Haskell类似,但类型类和大多数语法糖完全去糖化。Core的语义也与Haskell略有不同,特别是在它的case构造方面。在core中,case总是导致顶层构造函数的求值。模式被重写为嵌套,以匹配原始Haskell代码的模式语义。
这一节是题外话,但如果你研究优化Haskell代码,你会遇到核心问题,知道两者之间的区别是很有用的。

7gs2gvoe

7gs2gvoe2#

我的结论是,这一定是由于Haskell内的懒惰求值。而且,因为_匹配任何东西,它不会检查它与什么比较?
是的,没错!
在模式匹配过程中,只执行与模式中的构造函数(和数字/字符文字)匹配所需的求值。如果模式是变量或通配符_,则不需要求值。

case undefined of _ -> ()  -- OK
case undefined of True -> () -- crash
case undefined of (_,_) -> () -- crash
case (undefined, 4) of (_,x) -> x+1 -- OK

此外,模式匹配是从左到右、从上到下进行的:

case (4, undefined) of
   (3, True) -> 1
   (4, _)    -> 2

计算结果为2--我们首先将43进行匹配,在尝试将undefinedTrue进行匹配之前,3匹配失败。这样,我们避免了崩溃,第二个模式(4, _)成功。
(To详尽无遗:实际上有一个例外。如果你对一个newtype构造函数进行模式匹配,不会进行求值。你可以暂时忽略这种情况,因为你正在学习--它并不常见。)

相关问题