Learn You a Haskell解释了foldl1
:
foldl1和foldr1函数的工作方式与foldl和foldr非常相似 您不需要为它们提供明确的起始值。他们 假设列表的第一个(或最后一个)元素是起始元素 值,然后使用旁边的元素开始折叠。 ...
因为他们依赖于列表,所以他们折叠起来至少有一个 如果使用空列表调用它们会导致运行时错误
我认为它的实现或多或少是:
foldl1' :: (a -> a -> a) -> [a] -> a
foldl1' f ys = foldl f (head ys) (tail ys)
但是,这种潜在的运行时错误让我很烦恼。
为什么不以下列方式实施foldlOption
?
foldlOption :: (a -> a -> a) -> [a] -> Maybe a
foldlOption f [] = Nothing
foldlOption f ys = Just (foldl f (head ys) (tail ys))
REPL
*Main> foldlOption (\acc elem -> if (elem > acc) then elem else acc) []
Nothing
-- find max
*Main> foldlOption (\acc elem -> if (elem > acc) then elem else acc) [1,100,2,3]
Just 100
EDITED
更新了foldl1
和foldlOption
的定义,使用tail ys
作为foldl
的最后一个参数,而不是ys
每Lee Duhem个{{1}}纠正。
答案 0 :(得分:12)
实际上没有理由不这样做。 Haskell的前奏中的许多功能如head
,tail
,init
以及许多其他功能都会不必要地失败。
他们明确地指出他们在类型中的失败会更好,但不幸的是,当Prelude标准化时我们不能很好地改变像head
这样的几个核心功能!
现在我建议不要使用许多这些功能并选择模式匹配,或者加入Gabriel Gonzalez的errors库,它提供了前奏部分功能的替代版本,这些功能会失败。
例如在Control.Error.Safe
中有
foldl1Err :: e -> (a -> a -> a) -> [a] -> Either e a
并且错误也导出安全,类似的库Maybe
具有函数
foldl1May :: (a -> a -> a) -> [a] -> Maybe a
完全像你想要的那样:)