foldl实现运行时错误

时间:2014-04-20 15:05:57

标签: haskell

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

更新了foldl1foldlOption的定义,使用tail ys作为foldl的最后一个参数,而不是ysLee Duhem个{{1}}纠正。

1 个答案:

答案 0 :(得分:12)

实际上没有理由不这样做。 Haskell的前奏中的许多功能如headtailinit以及许多其他功能都会不必要地失败。

他们明确地指出他们在类型中的失败会更好,但不幸的是,当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

完全像你想要的那样:)