假设我有这个功能:
sales::Int->Int
此函数返回特定周的销售数量,周数被组织为一系列0,1,2 ....(它获取周数并返回该周的销售数量)
我需要定义函数zeroWeeks:zeroWeeks得到一个整数n并返回在[0 ... n]范围内有0个销售额的周数。 (周列表)
我用列表理解解决了它,
这就是我用列表理解解决它的方法:
zeroWeeks:: Int -> Int
zeroWeeks n = length(ans)
where ans = [w|w<-[0..n],sales w==0]
如何使用foldr函数解决它并且不使用递归?
答案 0 :(得分:1)
您可以定义一个辅助函数f
,如果某周的销售额为0,则返回1,否则为0。然后,您可以撰写+
和f
,将“零周”映射为1,将其他所有内容映射为0,然后取总和。
zeroWeeks :: [Int] -> Int
zeroWeeks = foldr ((+) . f) 0
where f w | sales w == 0 = 1
| otherwise = 0
答案 1 :(得分:1)
我认为使用手动递归而不是列表推导来查看函数的外观是个好主意:
zeroWeeks :: [Int] -> Int
zeroWeeks [] = 0
zeroWeeks (x:xs) = (if sales x == 0 then 1 else 0) + zeroWeeks xs
现在,让我们看看如何定义foldr
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
正如您所看到的,foldr是一种高级模式,用于定义类似于零周期的函数,z
代表基本情况,f
代表我们在递归中执行的操作案件。在zeroWeeks的情况下,很容易看出我们想让z
为0,而棘手的部分是找到f。基本上,我们需要做的是将x
和zeroWeeks xs
作为显式参数而不是biggger表达式的一部分:
zeroWeeks (x:xs) = (\x sum -> (if sales x == 0 then sum + 1 else sum)) x (zeroSum xs)
最终结果是
zeroSum xs = foldr (\x sum -> (if sales x == 0 then sum + 1 else sum)) 0 xs
虽然我强烈建议将这个大lambda函数重构为一个单独的函数以便于阅读,就像Benjamin Kovach在his answer中所做的那样。