我想定义min函数以使用Foldr函数
获取列表中的最小数字min xs = foldr (\ x y -> if x<y then x else y) xs
虽然我理解Foldr的逻辑,如下面的简单函数
sum = foldr (+) 0
我对如何为像min
这样的功能这样做感到困惑答案 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
的最佳方式。