【问题标题】:Why does this create a StackOverflow Error?为什么这会产生 StackOverflow 错误?
【发布时间】:2018-03-17 08:17:22
【问题描述】:

我最近开始使用 Haskell,并定义了这个看似简单的函数:

f 0 = 1
f x = x * f x - 1

但是,结果是这样的:

GHCi, version 8.2.1: http://www.haskell.org/ghc/  :? for help
Prelude> f 0 = 1
Prelude> f x = x * f x - 1
Prelude> f 10
*** Exception: stack overflow
Prelude>

【问题讨论】:

  • GHCi 没有意识到您正在定义 one 函数f。它逐行进行,因此f x = x * f x - 1 是一个函数f,它隐藏了f (f 0 = 1) 的先前定义。要输入多行块,请输入:{。使用:} 关闭该块。
  • 您的函数定义还使用f x 定义了f x。您的定义意味着f x = x * (f x) - 1,而不是x * (f (x - 1))
  • @Alec 没用:Prelude> :{ Prelude| f 0 = 1 前奏| f x = x * f x - 1 前奏| :} Prelude> f 10 *** 例外:堆栈溢出 Prelude>
  • @MarkNeu 当然不是,但不是出于同样的原因。请注意,x * f x - 1 被解析为 (x * f x) - 1。你的意思是x * f (x - 1)

标签: haskell ghci


【解决方案1】:

你的阶乘看起来是无辜的,但事实并非如此。解析如下:

f 0 = 1
f x = x * (f x) - 1

如果我们使用f 1会发生什么?

f 1 = 1 * (f 1) - 1 = 1 * (1 * (f 1) - 1) - 1
    = 1 * (1 * (1 * (f 1) - 1) - 1) - 1
    = 1 * (1 * (1 * (1 * (f 1) - 1) - 1) - 1) - 1
    = ...

我要在这里停下来。这永远不会结束。它会堆积一堆括号,有时整个塔会倒塌,最终导致堆栈溢出。

你必须使用括号:

f 0 = 1
f x = x * f (x - 1)

现在我们得到了正确的结果:

f 1 = 1 * f (1 - 1) = 1 * f 0 = 1 * 1 = 1

请记住,这仅适用于实现文件。在 GHCi 中,您必须使用多行模式或分号:

ghci> f 0 = 1; f x = x * f (x - 1)
ghci> -- or
ghci> :{
ghci| f 0 = 0
ghci| f x = x * f (x - 1)
ghci| :}

否则后面的定义会影响前面的定义。请注意,您的提示可能会有所不同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-27
    • 1970-01-01
    • 2017-12-06
    • 2020-10-11
    • 2016-02-08
    • 2013-06-06
    相关资源
    最近更新 更多