2010-08-22 123 views
16

我只是在學習Haskell,所以如果我的問題很愚蠢,那麼很抱歉。我正在閱讀learnyouahaskell.com,現在我正在閱讀第5章「遞歸」。有執行標準「反向」功能的一個例子:在線性時間運行的Haskell中執行反向操作

reverse' :: [a] -> [a] 
reverse' [] = [] 
reverse' (x:xs) = reverse' xs ++ [x] 

但是似乎它運行在O(N^2)時間,而標準反向的O(N)(我希望如此)運行。下面的代碼說明了這一點:

sum (reverse [1,2..1000000]) -- runs pretty fast 
sum (reverse' [1,2..1000000]) -- never finishes 

所以,我開始思考如何更快地實現我自己的反向。在命令式語言中做相當容易。也許我需要後續章節中的一些更高級的材料來做到這一點?歡迎任何提示。

回答

23

它可以有效地使用額外的蓄電池參數來實現的,像fac在這個例子中,第二個參數:

factorial n = fac n 1 
    where 
    fac 0 r = r 
    fac n r = fac (n-1) (r*n) 

如果你只是想知道它是如何在標準庫中完成的,你也可以look at the source code

12

reversePrelude中定義。

您可以實現它:

reverse = foldl (flip (:)) [] 
+0

難道這不會遭受'foldl'的經典堆棧問題嗎? – 2014-01-15 17:10:33

+0

Kru提供的版本直接來自源代碼。請注意,列表的內容不僅僅評估它們的位置。此外,如果您不使用整個反轉列表,則永遠不會創建列表。 – 2014-03-31 23:31:10

+1

@ 3noch我認爲'foldr'就是這種情況,而不是'foldl' – symbiont 2015-01-22 15:45:47

7
reverse l = rev l [] 
    where 
    rev []  a = a 
    rev (x:xs) a = rev xs (x:a) 
+0

這是來自GHC源https://下載的函數.haskell.org /〜GHC/6.12.1 /文檔/ HTML /庫/基層 - 4.2.0.0/SRC/GHC-List.html#反向。 – 2017-03-29 16:49:42

相關問題