将文字分配给 GHC 中的术语

问题描述

出于好奇,为什么是下面的程序

1 = 0

"hello" = "world"

有效且可由 GHC 编译?这仅仅是一个错误还是一个功能?谢谢!

解决方法

这是允许的,因为它是语言规则的自然结果,并没有大到足以在语言规范中设置特殊情况来阻止它的问题。

自然后果
有两种标准的定义:函数定义和数据定义。在函数定义中,你可以在等号左边写模式作为函数的参数。在数据定义中,您可以在等号左侧单独编写模式以匹配等号右侧的数据。所以,这些事情都是允许的:

x = 3
x@y = 3
[x,y,z] = [3,4,5]
[x,_,5]
x:_ = "xsuffix"
x:"suffix" = "xsuffix"

数字文字和字符串文字是模式。 (前者脱糖为调用 (==) 的守卫。)所以这些也是允许的:

3 = 3
x@3 = 3
[3,5] = [3,5]
"xsuffix" = "xsuffix"
-- and yes,these too
3 = 4
"xsuffix" = "lolno"

没问题
与语言的所有其他部分一样,数据定义是惰性的:它们表示的模式匹配计算在需要之前不会执行(通过检查匹配绑定的变量之一)。由于 "hello" = "world"1 = 0 不绑定任何变量,它们所代表的模式匹配计算——这将引发异常——永远不会执行。因此,避免允许它们并不是非常重要。

...除非是
但是等等......我们说这是一个有效的模式:

x@3 = 3

这个类似的发散并绑定一个变量:

x@3 = 4

为什么那个是允许的?这更难回答!我认为尝试考虑一些可以防止这种情况的语言规则是非常合理的。一般来说,一个健全且完备的规则当然是不可判定的,因为等式的右边可以进行任意计算。但是您还可以做出其他选择;例如:

  • 不允许在数据定义中使用可反驳的模式。如果模式可能无法匹配,则它是可反驳的。例如,x 是无可辩驳的,x@y 是无可辩驳的,_ 是无可辩驳的,但是 x:y 是可辩驳的,True 是可辩驳的,() 是可反驳的(因为当 RHS 处于底部时它会发散)。这是迄今为止最简单的,并且将排除 x@3 = 4"hello" = "world"。不幸的是,它也会排除非常有用的东西,例如 [x,5]
  • 实施终止检查器,并要求可反驳模式的 RHS 终止。如果您有一个分析可以决定某些计算终止——例如,通过发现其中的所有递归都是结构性的或其他东西,那么有一个终止检查算法的整个家庭手工业——那么您可以让编译器检查它。如果它确实终止,编译器实际上可以在编译期间运行计算,并仔细检查给定的模式实际上是否与值匹配。这样做的缺点是终止检查算法非常复杂,因此这给编译器编写者带来了很大的负担,并且有些是人类难以预测的,这使得针对它的编程让用户感到沮丧。
  • 要求程序员证明匹配不会失败。您可以为程序员引入一种机制来为他们的程序编写证明,并要求他们证明匹配不会失败。这朝着依赖类型的方向发展;此举的两个主要成本通常是程序效率的降低,以及使用此类语言编写程序需要付出更多努力。

语言设计者做出了许多选择(不仅仅是在模式匹配语义方面),这些选择在让程序员和编译器编写者的生活更轻松方​​面是错误的,但允许更多的程序抛出异常或永远不会完成。这是一个这样的地方 - 数据定义中允许可反驳的模式,即使这会导致崩溃,因为该策略的实施是有用的、简单的且可预测的。

,

因为这些文字是模式,所以您使用的是模式绑定。

Haskell 中的

let 绑定是懒惰,因此不会执行实际的模式匹配。

但是如果我们强制匹配,它确实失败了:

> :{
  let
    x@1 = 0
  in
    1
  :}
1                    -- no assignment!     NB
it :: Num a => a

> :{
  let
    x@1 = 0
  in
    x
  :}
*** Exception: <interactive>:87:1-7: Irrefutable pattern failed for pattern x@1

因为1确实不是 0

因此,这不是 GHC 实现的错误或功能,而是 Haskell 语言本身的功能。