Haskell非函数递归(或值递归或递归let绑定)
我是 Haskell 的新手,从第一原则开始阅读 Haskell。
在第 10 章第 378 页中,我遇到了这种新语法
fibs = 1 : scanl (+) 1 fibs
似乎 fibs 是一个函数 bcs 它在右侧被使用或调用
但它的类型是fibs :: Num a => [a]一个值
如何在它自己的定义中访问一个值?
如果我确实尝试查看 fibs 中的内容,它只会向无穷大打印。
和其他i = 1 + i完全有效语法的例子
,
但是当我在 ghci 旁边运行它时,它也会停止它。
- 如果它不是递归,它是什么类型的递归它是什么?
- 执行流程是什么?
i如果根本没有分配,如何在右侧访问?i右边第一次的价值是多少?i右边的值是什么?
任何可以帮助的文章?
回答
在许多(大多数?)语言中,函数是“特殊”值,在语言语法和语义中具有特殊地位。
在 Haskell 中,没有那么多。它们与非函数共享许多属性。特别是:
- 我们可以将函数(和非函数)作为参数传递给函数。
- 我们可以从函数返回函数(和非函数)。
- 我们可以将函数(和非函数)放入列表、对等容器中。
- 我们可以递归地定义函数(和非函数)。
最后一点如果你不习惯的话可能会令人费解,但是没有理由只在像 Haskell 这样的惰性语言中定义函数值时才允许递归。
例如,可以1:1:1:....通过让定义无限列表list = 1 : list。如果你只能理解函数的递归定义,只要知道它类似于list() = 1 : list(),除了list不是一个函数,而是一个列表。
您也可以尝试理解1:2:3:4:....可以递归定义为list = 1 : map (+1) list. 事实上,展开我们得到的定义:
list
= 1 : map (+1) list
= 1 : map (+1) (1 : map (+1) list)
= 1 : 2 : map (+1) (map (+1) list)
= 1 : 2 : map (+1) (map (+1) (1 : map (+1) list))
= 1 : 2 : 3 : map (+1) (map (+1) (map (+1) list))
...
请注意,上面的定义“有效”,因为它可以在递归需要自己的值之前生成值的一部分。在i = i + 1您提到的示例中,这不会发生,因为在产生输出的任何部分之前i + 1需要i立即的值。(嗯,至少在标准整数类型上是这样。)因此,它具有与我们从无限递归函数(例如 )中观察到的行为相同的行为i() = i() + 1。
- @hanan There is no specific name I know of, it's just recursion. Perhaps "recursion on values", "value recursion", but it's not a common term. You could try to google "lazy semantics" or "laziness" to understand it better: this kind of recursion is only meaningful in lazy (or non-strict) languages like Haskell. Otherwise, in an eager (or strict) language any non-function recursive definition would immediately cause non-termination, so language designers only allow recursion on functions.