【问题标题】:Why does this cause GHCI to hang?为什么这会导致 GHCI 挂起?
【发布时间】:2015-05-10 11:32:49
【问题描述】:

这段代码:

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 的原因,但它只是被添加到类型而不是值?

【问题讨论】:

  • stackoverflow.com/questions/21505192/…这个问题的答案应该是你要找的。​​span>
  • @SimonGibbons 是一样的;这是一个重复的问题。
  • @AJFarmar:它实际上不是重复的,因为另一个问题专门关于<<loop>> 输出,当卡在无限循环中时,ghci not 总是会产生该输出。

标签: haskell ghci


【解决方案1】:

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

是这样的:

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

等等……

【讨论】:

  • 递归调用在哪里?从 GHCI 调用 y 调用 y 一次?
  • @blue-sky 想想y的定义?
  • 从 ghci 调用 y 尝试评估 y,然后将其视为 y + 1,因为它知道 y 的定义,它将尝试将其扩展为 (y+1) +1 等等.....
【解决方案2】:

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

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

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

  3. 您可以提供有关单个值(类型声明)的元数据。这些对于缩小类型错误的范围非常有帮助,因为它们为类型推断算法设置了“墙”。它们还可以在添加多态性(Haskell 有一个“单态性限制”,这通常会影响新手)或将多态性限制为具体类型时产生语义效果。

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

这些都不是您向 Haskell 系统发出的命令;相反,您的文件是一个大的模块描述。类似地,在表达式中(上面的第一部分),您只能做几件事,而且它们通常不是必须的:您可以将值应用于其他值,创建函数,您可以创建本地定义 (let) 和模式匹配(case),您可以在本地添加类型元数据。其他所有内容,包括do 符号,只是执行上述这些操作的一种更方便的方式(“语法糖”)。

您的两个语句是类型声明(“此模块定义的 y 的类型将是整数”)和定义(“要计算此模块定义的 y,首先计算值y,然后添加一个“)。 Haskell 将它们一起读取并说:“哦,y 的类型为 Int,所以 (+) 是我所知道的特定 Int-Plus 操作,(+) :: Int -> Int -> Int,然后 1 是特定的 @987654348 @ 我知道的那个名字...。然后它将确认类型是自洽的并产生一些永远循环的命令式代码。

【讨论】:

    【解决方案3】:

    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 挂起。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-16
      • 2015-03-02
      • 2016-02-06
      • 2013-03-04
      • 1970-01-01
      相关资源
      最近更新 更多