【问题标题】:Stack overflow when defining Haskell Fibonacci定义 Haskell Fibonacci 时的堆栈溢出
【发布时间】:2020-06-06 15:14:57
【问题描述】:

只是试图做 Hal Daumé III 的 YAHT 手册的练习 3.7(第 31 页),我试图定义斐波那契函数:

fibo 1 = 1
fibo 2 = 1
fibo n = fibo(n-1) + fibo(n-2)

然后我要求

fibo(3)

得到:

*** Exception: stack overflow

当我查看练习的解决方案时,我发现了完全相同的代码(不同之处在于该函数被称为 fib 而不是 fibo)。我做错了什么?

(手册是 2006 年的,可能语言在中间发生了变化?) (讽刺的是,我向stackoverflow询问堆栈溢出的问题……)

【问题讨论】:

  • ghci 中的多行语句需要在:{:} 之间进行包装,否则您应该使用其他机制。现在您在第二行定义了一个新函数fibo,在第三行定义了另一个。

标签: haskell stack-overflow fibonacci


【解决方案1】:

这可能是在ghci 中一次一行定义函数的结果。这意味着您首先定义一个函数fibo 1 = 1。然后定义另一个函数,名称为fibo(带有fibo 2 = 2),其范围更广,最后定义第三个函数,名为fibo

您可以在:{:} 之间包装多行函数,从而定义由三个子句组成的一个函数fibo

Prelude> :{
Prelude| fibo 1 = 1
Prelude| fibo 2 = 1
Prelude| fibo n = fibo (n-1) + fibo (n-2)
Prelude| :}
Prelude> fibo 3
2

【讨论】:

  • 谢谢!顺便说一句,我有一个问题:在一个程序中,向用户询问一个数字,程序回答“太高了!”或“太低了!”直到用户猜对了数字,才会有一个 Haskell 代码行 guess <- getLine,然后使用 guess。这不像在命令式语言中使用变量吗?这个guess 与Perl 中的$guess 有什么区别,只要用户输入一个新数字就会得到一个新值?
  • @yannis:不。事实上do 符号只是语法糖。如果你写x <- foo; bar x,它将被重写为foo >>= \x -> bar x。此外,就像 Haksell 中的所有数据一样,变量是不可变的。因此,一旦设置,您将永远无法将变量设置为不同的值。所以do 没什么“特别”的。实际上,它只是一种语法,可以更方便地使用“绑定”函数>>= 编写长链。此外,您可以将do 用于各种单子,例如IOMaybeQ[] 等。
  • @yannis do 块可能看起来确实像命令式编程,但它不是一回事。尽管如此,在我们有 guess <- getLine 的基于递归 IO 的块中,您可以期望 guess 每次都从用户那里获得新值,非常类似于命令式编程。请注意,我们这里没有可变变量,每个递归调用都会创建自己的“本地”guess 变量并将其绑定到一个值。要真正了解 IO,我建议阅读一些 IO 教程。
  • @Willem 这对新手没有帮助。 :) 是的,foo = do { x <- getLine ; printResponse x ; foo } 中的 x 就像一个命令式变量被一遍又一遍地覆盖在循环中(任何自尊的实现都应该编译该代码,我希望如此非常多),尽管有实现细节。 IIRC,某处有一个“没有 monads 的 IO”教程。
  • @WillNess:它给人一种错误的印象,例如x <- getLine; do {x <- getLine }; print x 会打印由内部getLine 设置的值。但事实并非如此,因为那是本地范围的。所以变量的重新赋值与 Perl 中的不同。不幸的是,很多关于 Haskell 的问题都来自不理解这一点的人。
猜你喜欢
  • 2011-08-22
  • 1970-01-01
  • 2019-07-08
  • 2015-08-05
  • 1970-01-01
  • 1970-01-01
  • 2015-01-07
  • 2019-05-18
  • 2011-11-23
相关资源
最近更新 更多