问题描述
我有两个功能。如果列表的所有元素都为零,则第一个返回 true
allZero :: [Int] -> Bool
allZero [] = False
allZero [0] = True
allZero (x:xs)
| x == 0 && allZero xs = True
|otherwise = False
oneZero :: [Int] -> Bool
oneZero [] = False
oneZero (x:xs)
| x == 0 = True
| otherwise = oneZero xs
也许有另一种方法可以解决这个问题。例如使用地图或文件夹? 谢谢
解决方法
foldr
基本上把你的守卫作为它的折叠功能:
allZero = foldr (\x acc -> x == 0 && acc) True
acc
(用于 accumulator)是递归调用的已计算值。由于是右结合,列表中的第一个非零值会使列表其余部分的折叠函数的计算短路。
(注意 allZero [] == True
按照惯例。“假设”是 allZero xs
为真,有非零元素形式的证据来证伪假设。列表中没有元素,没有证据与假设相矛盾。)
我把它留作练习来调整它以计算 oneZero
。
foldr
函数是这样工作的:
假设您有列表 [1,2,3]
。让我们将此列表写为 (:) 1 ((:) 2 ((:) 3 []))
,其中每个元素的类型为 a
。函数foldr
采用f
类型的函数a -> b -> b
和z
类型的起始元素b
,只需将[]
替换为z
和 :
到 f
。所以,foldr f z ((:) 1 ((:) 2 ((:) 3 []))) == f 1 (f 2 (f 3 z))
。
所以,你可以这样定义你的函数:
allZero = foldr (\x -> x == 0 &&) True
oneZero = foldr (\x -> x == 0 ||) False