为什么这会导致 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 的列表。它是一种不同风格的编程语言。相反,您可以访问几种顶级语句:
您可以定义值。 y = y + 1
将符号 y
定义为函数 (+)
对另外两个参数 y
和 1
的应用。该定义贯穿文件,特别是在定义之上和在定义之内的事物。因此,您完全可以在 .hs
文件中写入 y = x + 1
然后 x = 2
,然后向 GHCi 询问 y
,它会说 3
。请注意,使用 let
关键字会变得更加复杂,它形成了 "wall" 定义的扩展性质: let
接受定义块和值表达式并将这些定义范围限定为在组合的(定义块,值表达式)上下文中,但将这些定义与 let
之外的世界隔离开来。所以这也是有效的:
Prelude> let y = x + 1; x = 2
Prelude> y
3
您可以定义数据结构及其构造函数。构造函数是我们允许参与 模式匹配 的特殊函数:换句话说,Haskell 知道如何 反转 或解构 每个构造函数。您还可以定义一个 type
同义词和一个 newtype
,它们介于两者之间。
您可以提供有关单个值的元数据(类型声明)。这些对于缩小类型错误的范围确实很有帮助,因为它们为类型推断算法设置了 "wall"。它们还可以在添加多态性(Haskell 有一个 "monomorphism restriction" 经常咬新人)或将该多态性限制为具体类型方面产生语义影响。
您可以提供关于整个包的元数据:它如何合并其他包(导入语句)以及它如何被其他包使用(模块语句)。
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 挂起。
此代码:
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 的列表。它是一种不同风格的编程语言。相反,您可以访问几种顶级语句:
您可以定义值。
y = y + 1
将符号y
定义为函数(+)
对另外两个参数y
和1
的应用。该定义贯穿文件,特别是在定义之上和在定义之内的事物。因此,您完全可以在.hs
文件中写入y = x + 1
然后x = 2
,然后向 GHCi 询问y
,它会说3
。请注意,使用let
关键字会变得更加复杂,它形成了 "wall" 定义的扩展性质:let
接受定义块和值表达式并将这些定义范围限定为在组合的(定义块,值表达式)上下文中,但将这些定义与let
之外的世界隔离开来。所以这也是有效的:Prelude> let y = x + 1; x = 2 Prelude> y 3
您可以定义数据结构及其构造函数。构造函数是我们允许参与 模式匹配 的特殊函数:换句话说,Haskell 知道如何 反转 或解构 每个构造函数。您还可以定义一个
type
同义词和一个newtype
,它们介于两者之间。您可以提供有关单个值的元数据(类型声明)。这些对于缩小类型错误的范围确实很有帮助,因为它们为类型推断算法设置了 "wall"。它们还可以在添加多态性(Haskell 有一个 "monomorphism restriction" 经常咬新人)或将该多态性限制为具体类型方面产生语义影响。
您可以提供关于整个包的元数据:它如何合并其他包(导入语句)以及它如何被其他包使用(模块语句)。
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 挂起。