我目前正在学习 haskell 和碰撞到这个表达式。
statement case 1 ´div´ 0 of _ -> 42
我的直觉是,这将导致运行时错误,因为除法为0,但从测试来看,情况并非如此。我的结论是,这一定是由于Haskell内的懒惰求值。而且,因为_匹配任何东西,它不会检查它与什么比较?因此,如果有人能告诉我,如果这个评估是正确的,如果不是为什么。也请详细说明什么前提下,一个案件行可以匹配,而不实际上看表达式。
_
ymdaylpp1#
“你的分析很准确,但这实际上是非常精细的。它并不复杂,但它需要仔细考虑非常精确的问题。”在 haskellcase表达式的一般形式为
case exp0 of {pat1 -> exp1 ; ...}
在计算case表达式时,exp0的计算结果足以确定它是否与pat1匹配。如果匹配,case表达式将使用为它创建的任何附加绑定pat1来计算exp1。如果不匹配,则福尔斯下一个模式或保护并重复。(如果没有匹配,则计算为异常。)值得注意的是,你的第一个选择匹配所有的东西,而不需要任何求值,所以没有对div 1 0求值,模式不绑定任何东西,然后case表达式求值为42。这与您执行以下操作的情况不同:
exp0
pat1
exp1
div 1 0
case 1 `div` 0 of 0 -> 42 _ -> 42
在这种情况下,必须计算div表达式以查看它是否等于0。这将导致异常,该异常将成为整个case表达式的结果。即使两个分支具有相同的值,也是如此。模式的内容对于确定与严格性相关的行为非常重要。
div
GHC Haskell编译器是目前最常见的编译器,它有一个称为“core”的中间表示,看起来与Haskell类似,但类型类和大多数语法糖完全去糖化。Core的语义也与Haskell略有不同,特别是在它的case构造方面。在core中,case总是导致顶层构造函数的求值。模式被重写为嵌套,以匹配原始Haskell代码的模式语义。这一节是题外话,但如果你研究优化Haskell代码,你会遇到核心问题,知道两者之间的区别是很有用的。
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--我们首先将4与3进行匹配,在尝试将undefined与True进行匹配之前,3匹配失败。这样,我们避免了崩溃,第二个模式(4, _)成功。(To详尽无遗:实际上有一个例外。如果你对一个newtype构造函数进行模式匹配,不会进行求值。你可以暂时忽略这种情况,因为你正在学习--它并不常见。)
2
4
3
undefined
True
(4, _)
newtype
2条答案
按热度按时间ymdaylpp1#
“你的分析很准确,但这实际上是非常精细的。它并不复杂,但它需要仔细考虑非常精确的问题。”
在 haskell
case表达式的一般形式为
在计算case表达式时,
exp0
的计算结果足以确定它是否与pat1
匹配。如果匹配,case表达式将使用为它创建的任何附加绑定pat1
来计算exp1
。如果不匹配,则福尔斯下一个模式或保护并重复。(如果没有匹配,则计算为异常。)值得注意的是,你的第一个选择匹配所有的东西,而不需要任何求值,所以没有对
div 1 0
求值,模式不绑定任何东西,然后case表达式求值为42。这与您执行以下操作的情况不同:
在这种情况下,必须计算
div
表达式以查看它是否等于0。这将导致异常,该异常将成为整个case表达式的结果。即使两个分支具有相同的值,也是如此。模式的内容对于确定与严格性相关的行为非常重要。核心
GHC Haskell编译器是目前最常见的编译器,它有一个称为“core”的中间表示,看起来与Haskell类似,但类型类和大多数语法糖完全去糖化。Core的语义也与Haskell略有不同,特别是在它的case构造方面。在core中,case总是导致顶层构造函数的求值。模式被重写为嵌套,以匹配原始Haskell代码的模式语义。
这一节是题外话,但如果你研究优化Haskell代码,你会遇到核心问题,知道两者之间的区别是很有用的。
7gs2gvoe2#
我的结论是,这一定是由于Haskell内的懒惰求值。而且,因为
_
匹配任何东西,它不会检查它与什么比较?是的,没错!
在模式匹配过程中,只执行与模式中的构造函数(和数字/字符文字)匹配所需的求值。如果模式是变量或通配符
_
,则不需要求值。此外,模式匹配是从左到右、从上到下进行的:
计算结果为
2
--我们首先将4
与3
进行匹配,在尝试将undefined
与True
进行匹配之前,3
匹配失败。这样,我们避免了崩溃,第二个模式(4, _)
成功。(To详尽无遗:实际上有一个例外。如果你对一个
newtype
构造函数进行模式匹配,不会进行求值。你可以暂时忽略这种情况,因为你正在学习--它并不常见。)