Haskell 为什么这会导致GHCI被绞死?
此代码:Haskell 为什么这会导致GHCI被绞死?,haskell,ghci,Haskell,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+1的y。那么评估将如何进行 事情是这样的: y y + 1 (y + 1) + 1 (
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+1
的y
。那么评估将如何进行
事情是这样的:
y
y + 1
(y + 1) + 1
((y + 1) + 1) + 1
等等……更广泛地说,Haskell文件(或GHCi)不像其他编程语言那样包含命令/顺序列表。它是一种不同风格的编程语言。相反,您可以访问以下几种顶级语句:
y=y+1
将符号y
定义为将函数(+)
应用于两个其他参数y
和1
。此定义贯穿整个文件,尤其是定义之上和定义内的内容。因此,您可以完全写入y=x+1
,然后在.hs
文件中写入x=2
,并向GHCi请求y
,它会说3
。请注意,let
关键字使这一点变得更为复杂,它构成了定义扩展性质的“墙”:let
接受定义块和值表达式,并将这些定义限定在组合(定义块、值表达式)上下文中,但是这些定义与let
之外的世界隔绝了。所以这也是有效的:
Prelude> let y = x + 1; x = 2
Prelude> y
3
类型
同义词和一个新类型
,它介于两者之间let
)和模式匹配(case
),您可以在本地添加类型元数据。其他的一切,包括do
notation,只是做上述事情的一种更方便的方式(“语法糖”)
您的两条语句是类型声明(“此模块定义的
y
的类型将是整数”)和定义(“要计算此模块定义的y
,请首先计算y
的值,然后向其中添加一个”)。Haskell把它们一起读了一遍,然后说,“哦,y
的类型是Int
,所以(+)
是我知道的特定Int-Plus操作,(+)::Int->Int->Int
,然后1
是我所知道的该名称的特定Int
。然后它将确认类型是自一致的,并生成一些永久循环的命令代码。Haskell没有变量,只有常量,因此,您不能使用与其他语言相同的样式s、 但是,这确实意味着,你可以做一些非常棒的事情,这是你偶然发现的
以这一声明为例:
myList = 1 : myList
在进行评估时,它将引用自身,因此执行以下操作:
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挂起。这个问题的答案应该是您要找的。@SimonGibbons完全相同;这是一个重复的问题。@AJFarmar:实际上不是重复的,因为另一个问题是关于
ou的tput,当陷入无限循环时,ghci不总是产生哪个。递归调用在哪里?从ghci调用y调用y一次?@蓝天尝试思考y
?从ghci调用y尝试计算y
,然后将其视为y+1
,因为它知道y
它将尝试将其扩展为(y+1)+1
,以此类推。。。。。