Haskell中无限的斐波那契数列列表。

3
抱歉出现这样的问题。我是一个非常初级的程序员,刚开始学习Haskell。最近我遇到了一个练习,在Haskell中实现一个返回无限斐波那契数列的函数。以下代码是答案:
fibs :: [Int]
fibs = fibs2 0
 where
    fibs2 :: Int -> [Int]
    fibs2 x = (fib2) x : (fibs2 (x+1))

有人能解释一下为什么我们需要在这里声明另一个函数(fibs2)以及在这种情况下“where”是什么意思吗?

4
fib2如何定义? - jpmarinier
where 引入了一个本地定义,并且在大多数 Haskell 的介绍中都有早期的涵盖。 - molbdnilo
fib2没有定义!! - Vanillo.schnitzel
它如何生成无限列表? - Vanillo.schnitzel
1
fib2 看起来是一个函数,它返回第 i 个斐波那契数。fibs2 是一个函数,它通过一次计算一个斐波那契数,然后递归生成 其余 的斐波那契数来构建列表。 - chepner
1个回答

4
有人能向我解释一下为什么我们要在这里声明另一个函数(fibs2)吗?
你并不一定要声明另一个函数。然而,这种模式非常常见。可以将它看作其他语言中的循环初始化。如果想迭代某个过程,则最简单的方法是编写一个函数,该函数接收描述迭代位置的信息,执行一步“循环”,然后使用适当修改的描述调用自身。例如,如果要计算从0到n的所有数字的总和,则可以编写以下代码:
sumTo :: Int -> Int
sumTo 0 = 0
sumTo n = n + foo (n-1)

但是经常情况下,您想要的功能或值实际上是从特定值开始的那个。强制所有循环调用者指定起始值是很烦人的;而且你实现循环作为具有参数的递归函数的事实是一个他们不必担心的实现细节。那么该怎么办呢?嗯,您定义一些使用正确起始值调用循环的东西。

gauss :: Int
gauss = sumTo 100

这种方法使得用户只需要使用gauss,而不用知道100是内部函数正确的起始值。

有人可以解释一下在这种情况下,“where”是什么意思吗?

嗯,我们之前的sumTo/gauss值有个问题:我们并不真正关心sumTo本身,而只是关心gauss,而它可见于gauss之外,这违反了抽象屏障!如果很容易被调用,可能会有其他人尝试使用它;然后,如果我们需要改进gauss来改善其功能,我们正在改善gauss,但可能会破坏其他用户正在使用sumTo的内容。因此,我们希望隐藏它的存在。

这就是where的目的:它允许您定义一个仅在本地可访问的新内容。所以:

gauss :: Int
gauss = sumTo 100 where
    sumTo 0 = 0
    sumTo n = n + sumTo (n-1)

在这个变体中,可以调用gauss,但在gauss的实现之外,不可能调用sumTo,以保持良好的抽象边界。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接