我不打算去算法本身,但這裏有一些關於如何構建遞歸函數的建議。
首先,這裏你將如何格式化一個單獨的文件代碼
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