我不打算去算法本身,但这里有一些关于如何构建递归函数的建议。
首先,这里你将如何格式化一个单独的文件代码
fibo :: Integral x => [x]->x->x->x->[x]
fibo l x y 0 = l
fibo l x y n = fibo (l ++ [y+x] ++ [y+x+y]) (x+y) (y+x+y) (n-1)
如果您保存此为fibo.hs,那么你就可以
ghci fibo.hs
开始GHCI加载文件在开始时。你也可以用命令
:l fibo.hs
(assumming您在保存fibo.hs相同的目录开始GHCI)
另一个优点是,现在当你编辑的文件开始GHCI后加载文件,只需在GHCi提示符下输入
:r
即可重新加载所有更改。
现在,为了摆脱额外的参数,Haskell中的常规模式是将递归部分重构为其自身的辅助函数,并将主函数作为仅接受必要参数的入口点。例如,
fibo :: Integral x => x -> [x]
fibo n = fiboHelper [0,1] 0 1 n
fiboHelper :: Integral x => [x]->x->x->x->[x]
fiboHelper l x y 0 = l
fiboHelper l x y n = fiboHelper (l ++ [y+x] ++ [y+x+y]) (x+y) (y+x+y) (n-1)
现在,您可以拨打fibo
简单地
> fibo 3
[0,1,1,2,3,5,8,13]
此外,一个辅助函数像这样的是没有用的本身通常是隐藏在主函数中的使用let
内部函数或where
。
fibo :: Integral x => x -> [x]
fibo n = fiboHelper [0,1] 0 1 n where
fiboHelper l x y 0 = l
fiboHelper l x y n = fiboHelper (l ++ [y+x] ++ [y+x+y]) (x+y) (y+x+y) (n-1)
像这样的内部函数通常给出一个较短的名称,因为背景使得其目的明确,所以我们可以将名称更改为如fibo'
。
go
是递归辅助函数的另一个常用名称。
你可以像你的解释(无需包裹将它写在一个文件中逐行一切都放在let块中),然后在解释器中加载文件(在GHCi中使用:l filename) – Cubic 2012-07-25 18:58:02
您的代码是尾递归的,但效率非常低,因为(++)在其第一论据。但我想这不是问题的一部分。 – 2012-07-25 18:58:25
Haskell中的尾递归不像使用严格的语言那样需要不断的堆栈使用,反之非尾递归也不需要线性堆栈使用,所以我质疑您的练习的价值。坦率地说,我会用经典的'fibs = 0:1:zipWith(+)fibs(tail fibs)'或者其中一个变体'scanl'或'unfoldr'。看到[这个HaskellWiki页面](http://www.haskell.org/haskellwiki/The_Fibonacci_sequence)的一堆实现。 – 2012-07-25 20:13:50