2017-03-03 21 views
3

如何在遞歸調用鏈中向後傳播信息?以遞歸調用向後傳播信息

例如:

f :: [Int] -> [Int] 
f (x:xs) 
    | x `mod` 17 = ... 
    | otherwise = (x + 1) : f xs 
f [] = [] 

我想在...停止評價,我也希望這些信息傳播給調用者(事實上,它已停止)。我嘗試使用類似Maybe的返回類型,但之後必須對遞歸調用進行模式匹配,從而失去了尾部調用優化,因爲我必須在調用返回後對其進行評估(注意:可以輕鬆地將上述代碼轉換爲TR形式,但我爲了更容易理解而將其留下)。

你能想出一個更好的解決方案,仍然TCO中獲益?

+0

我投票結束這個問題作爲題外話,因爲它不再是一個問題(OP計算出來) – luqui

+5

尾遞歸不如在哈斯克爾守護遞歸重要。 https://wiki.haskell.org/Tail_recursion – chepner

+0

也與此有關:*?哈斯克爾是否有尾遞歸優化*](http://stackoverflow.com/q/13042353/2751851) – duplode

回答

3

您可以隨時使用額外的參數,並與積累的結果返回的元組。這樣,您仍然從TCO中獲益,並獲得所需的信息。

一個例子:

f :: [Int] -> Bool -> [Int] -> (Bool, [Int]) 
f (x:xs) l accum 
    | x `mod` 17 == 0 = (False, accum) 
    | otherwise  = f xs l ((x+1) : accum) 
f [] l accum = (True, accum) 

或者在一個更優雅的方式:

data CheckedValue a = Valid a | Invalid a 
    deriving Show 

f :: [Int] -> [Int] -> CheckedValue [Int] 
f (x:xs) accum 
    | x `mod` 17 == 0 = Invalid accum 
    | otherwise  = f xs ((x+1) : accum) 
f [] accum = Valid accum 

注意:這些功能也扭轉名單,但不注重這一點。