使用foldr
时,递归会在函数内部出现,因此,
当给定的函数不严格评估双方时,和
可以根据第一个返回,foldr
必须是一个很好的解决方案,
因为它适用于无限列表
findInt :: Int -> [Int] -> Bool
findInt z [] = False
-- The recursion occours inside de given function
findInt z (x:xs)
| z == x = True
| otherwise = findInt z xs
相当于:
findInt' :: Int -> [Int] -> Bool
findInt' z = foldr (\x r -> if z == x then True else r) False
-- Where False is the "default value" (when it finds [], ex: findInt z [] = False)
foldr
不合适的情况:
addAll :: Int -> [Int] -> Int
addAll z [] = z
-- The recursion occours outside the given function (+)
addAll z (x:xs) = addAll (z + x) xs
在这种情况下,因为+是严格的(需要评估双方返回) 如果我们以某种方式应用它,它将非常有用 有一个 redex (可简化的表达式),可以避免thunk 并且(当被迫与先前的评估一起运行,而不是懒惰)在常量中 空间并没有推到堆栈上 (类似于命令式算法中for循环的优点)
addAll' :: Int -> [Int] -> Int
addAll' z [] = z
addAll' z (x:xs) = let z' = z + x
in seq z' $ addAll' z' xs
相当于:
addAll'' :: Int -> [Int] -> Int
addAll'' z = foldl' (+) z
在这个小例子中,使用foldr(内部递归)没有意义 因为它不会制作重新索引。 它会是这样的:
addAll''' :: Int -> [Int] -> Int
addAll''' z [] = z
addAll''' z (x:xs) = (+) x $ addAll''' z xs
这个问题的主要目的是首先,知道我的前提是否属于 正确或可能更好的地方,其次,帮助使其更清晰 对于其他人谁也在学习 Haskell 内部和内部之间的差异 外部递归,在这些方法中,要记住哪一个 可能更适合特定情况
有用的链接:
答案 0 :(得分:2)
除了foldr是列表的自然catamorphism,而foldl和foldl'不是,它们的一些使用指南:
作为旁注,我相信您使用术语“内部递归”来定义foldr和foldl和foldl'的“外部递归”,但我之前在文献中没有看到这些术语。更常见的是,这些函数分别被称为从右侧折叠和从左侧折叠,这些术语虽然可能不完全正确,但它们给出了列表元素传递给函数的顺序的良好概念。