使用Foldr定义最小函数

时间:2014-07-11 04:46:06

标签: haskell functional-programming

我想定义min函数以使用Foldr函数

获取列表中的最小数字
min xs  = foldr (\ x y -> if x<y then x else y) xs

虽然我理解Foldr的逻辑,如下面的简单函数

sum     = foldr (+) 0

我对如何为像min

这样的功能这样做感到困惑

2 个答案:

答案 0 :(得分:3)

foldr的类型签名是:

foldr :: (a -> b -> b) -> b -> [a] -> b

特别是,foldr有三个参数,因此缺少min的定义 一个值:

min xs  = foldr (\ x y -> if x<y then x else y) ??? xs

对于sum = foldr (+) 0,参数0是空列表中sum的值。

同样,缺少的论点???应该是空列表中min的值。但min []甚至没有任何意义吗?

解决这个问题的方法是要意识到只应在非空列表上调用min并写:

min [] = error "min called on an empty list"

min (a:as) = foldr (\x y -> if x < y then x else y) ??? as 

确定什么???应该问问自己:min (a:as)时应该as = []应该做什么?

答案 1 :(得分:1)

min最好被视为折叠而不是折叠。正确折叠方法的问题在于,在列表已经完全遍历之前不会进行比较。如果列表是懒惰生成的,这将导致大量过多的内存使用。即使不是,也可能导致缓存使用不当和总体缓慢。这个答案的其余部分不那么实用。

正如http://www.haskell.org/haskellwiki/Foldl_as_foldr所示,实际上可以用foldl来写foldr

foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f a bs =
   foldr (\b g x -> g (f x b)) id bs a

总的来说,这不是一个很好的实现,但是程序转换的最新发展实际上已经使它工作正常,显然,虽然可能不是在实际发布的编译器中!

然后

foldl1 f (a:as) = foldl f a as
                = foldr (\b g x -> g (f x b)) id as a

现在写

min2 x y
  | x <= y = x
  | otherwise = y

然后

min = foldl1 min2

所以我们可以写

min (a:as) = foldr (\b g x -> g (min2 x b)) id as a

和(在最前沿的研究编译器上)这可能是使用foldr实施min的最佳方式。