为什么这会导致 GHCI 挂起?

Why does this cause GHCI to hang?

此代码:

y :: Int
y = y + 1

执行时会导致 GHCI 挂起。

y :: Int; this means y is of type Int
y = y + 1; this means y is defined to be an Int + 1

如果我对语句的定义不正确,请纠正我。

为什么y不评价?

y 被添加到 Int 的原因是什么,但它只是被添加到一个类型而不是一个值?

那是因为它无限递归。您正在调用 y,它被定义为 y + 1。那么评估将如何进行?

它是这样的:

y
y + 1
(y + 1) + 1
((y + 1) + 1) + 1

等等...

更广泛地说,Haskell 文件(或 GHCi)不像其他一些编程语言那样包含 imperatives/orders 的列表。它是一种不同风格的编程语言。相反,您可以访问几种顶级语句:

  1. 您可以定义值。 y = y + 1 将符号 y 定义为函数 (+) 对另外两个参数 y1 的应用。该定义贯穿文件,特别是定义之上和定义之内的事物。因此,您完全可以在 .hs 文件中写入 y = x + 1 然后 x = 2,然后向 GHCi 询问 y,它会说 3。请注意,使用 let 关键字会变得更加复杂,它形成了 "wall" 定义的扩展性质: let 接受定义块和值表达式并将这些定义范围限定为在组合的(定义块,值表达式)上下文中,但将这些定义与 let 之外的世界隔离开来。所以这也是有效的:

    Prelude> let y = x + 1; x = 2
    Prelude> y
    3
    
  2. 您可以定义数据结构及其构造函数。构造函数是我们允许参与 模式匹配 的特殊函数:换句话说,Haskell 知道如何 反转 解构 每个构造函数。您还可以定义一个 type 同义词和一个 newtype,它们介于两者之间。

  3. 您可以提供有关单个值的元数据(类型声明)。这些对于缩小类型错误的范围确实很有帮助,因为它们为类型推断算法设置了 "wall"。它们还可以在添加多态性(Haskell 有一个 "monomorphism restriction" 经常咬新人)或将该多态性限制为具体类型方面产生语义影响。

  4. 您可以提供关于整个包的元数据:它如何合并其他包(导入语句)以及它如何被其他包使用(模块语句)。

None 其中 订单 是您给 Haskell 系统的;相反,您的文件都是一大堆 模块描述 。类似地,在一个表达式(上面的第一部分)中,您只能做几件事,而且它们通常不是命令式的:您可以将值应用于其他值,创建函数,您可以创建本地定义(let ) 和模式匹配 (case),并且您可以在本地添加类型元数据。其他一切,包括 do 符号,只是一种更方便的方式 ("syntactic sugar") 来执行上述操作。

您的两个语句是类型声明 ("the type of the y defined by this module will be an integer") 和定义 ("to compute a y as defined by this module, first compute the value of a y, then add one to it")。 Haskell 将它们一起读取并说,“哦,y 具有类型 Int,因此 (+) 是我知道的特定 Int-Plus 操作,(+) :: Int -> Int -> Int,然后 1 是我知道的那个名字的特定 Int...。然后它将确认类型是自洽的,并生成一些永远循环的命令式代码。

Haskell没有变量,只有常量,因此,您不能使用与其他语言相同的样式,可更新的值指的是最后一个。然而,这确实意味着您可以做一些非常棒的事情,而这些事情您已经被绊倒了。

以此声明为例:

myList = 1 : myList

计算时,this 将引用自身,因此这样做:

myList = 1 : myList                      -- but I'm referring to myList, so...
myList = 1 : (1 : myList)                -- but I'm referring to myList, so...
myList = 1 : (1 : (1 : myList))          -- but I'm referring to myList, so...
myList = 1 : 1 : 1 : 1 : 1 : 1...        -- etc.

你的常量也是如此 y:

y = y + 1             -- but I'm referring to y, so...
y = y + 1 + 1         -- but I'm referring to y, so...
y = y + 1 + 1 + 1     -- but I'm referring to y, so...
y = 1 + 1 + 1 + 1 ... -- etc.

GHCi 永远无法完全计算 y 的值,因为它是无限的,导致 GHCi 挂起。