在递归调用中向后传播信息

时间:2017-03-03 01:48:56

标签: haskell recursion

如何在递归调用链中向后传播信息?

例如:

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

我想在...处停止评估,并且我还希望将该信息传播回调用者(事实上它已停止)。我尝试使用像Maybe这样的返回类型,但后来我不得不对递归调用进行模式匹配,从而丢失尾调用优化,因为我必须在返回调用后对其进行评估(注意:可以轻松地将上面的代码转换为TR形式,但为了更容易理解,我把它留下了。

你能想出一个更好的解决方案,仍然可以从TCO中受益吗?

1 个答案:

答案 0 :(得分: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

注意:这些功能也会反转列表,但不会注意这一点。