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
    
  • 您可以定义数据结构及其构造函数。构造函数是我们允许参与模式匹配的特殊函数:换句话说,Haskell知道如何反转或分解每个构造函数。您还可以定义一个
    类型
    同义词和一个
    新类型
    ,它介于两者之间

  • 您可以提供有关单个值(类型声明)的元数据。这对于缩小类型错误的范围非常有用,因为它们为类型推断算法设置了一道“墙”。它们还可以在添加多态性(Haskell有一个“单态限制”,经常会咬新来者)或将多态性限制为具体类型方面产生语义效应

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

  • 这些都不是你给Haskell系统的命令;相反,您的文件都是模块的一个大描述。类似地,在表达式(上面的第一部分)中,您只能执行几项操作,而这些操作通常不是必需的:您可以将值应用于其他值,创建函数,您可以创建本地定义(
    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
    ,以此类推。。。。。