递归循环数

时间:2018-10-06 08:07:07

标签: haskell recursion

我想计算列表中正整数/元素的数量。这将返回具有正值的元素,我该如何计算元素?想要构造类似count(array(...))的东西。

我希望看到带有 i ++ foldl 的版本。那会很有帮助。

countPositivesRec :: [Int] -> [Int]
countPositivesRec [] = []
countPositivesRec (x:xs) | x >= 0 = x : tl
                         | otherwise = tl
                           where tl = countPositivesRec xs

3 个答案:

答案 0 :(得分:1)

这里有个提示:遵循与以前相同的递归方案,但是在每个步骤都返回一个int。

countPositivesRec :: [Int] -> Int
                              ---
countPositivesRec [] = 0 -- no positives in the empty list
countPositivesRec (x:xs) | x >= 0    = ??
                         | otherwise = ??
                          where tl = countPositivesRec xs

您可以解决这个问题,如果需要,可以使用foldr进行重写。

如果您真的想使用foldl,建议您先定义一个函数f,这样

f (f (f 0 x0) x1) x2

求出x0,x1,x2中的正数。然后,您可以使用foldl f 0 inputList

答案 1 :(得分:1)

您编写的函数为filter (>=0)。正如Paul所指出的,剩下的唯一步骤就是计数,length做到了。我们可以逐步转换功能:

countPositivesRec :: [Int] -> [Int]
countPositivesRec [] = []
countPositivesRec (x:xs) | x >= 0 = x : tl
                         | otherwise = tl
                           where tl = countPositivesRec xs

请注意,xs仅以转换后的形式tl使用。这就是让它正确折叠的原因。

onlypos1 = foldr maybekeep []
  where maybekeep x tl | x >= 0    = x : tl
                       | otherwise = tl

此操作称为filter,仅保留部分内容:

onlypos2 = filter dowekeep
  where dowekeep x = x >= 0
onlypos3 = filter (\x -> x >= 0)
onlypos4 = filter (>= 0)

但这当然只是许多可能方法中的一种。例如,严格性分析可以得出这样的结论:lengthfoldl' (\a _ -> succ a) 0更好地实现为foldr (\_ a -> succ a) 0。确实,这是前奏曲中的基本形式:

length = foldl' (\c _ -> c+1) 0

我们看到length的组合函数忽略了一个参数的值,只要求它存在。这可以自然地与我们只需要某些元素计数的条件合并:

lengthFilter1 = length . filter
lengthFilter2 pred = foldl' predCount 0
  where predCount c x = if pred x then c+1 else c
countNonNegative = lengthFilter2 nonNegative
  where nonNegative x = x >= 0

顺便说一句,0不是正数。这是非负的。

最后,Haskell的惰性列表意味着我们可以使用它们来融合遍历。 length . filter (>=0)只读取一次输入列表,因为它处理filter的结果的唯一原因是length消耗了它们。与例如Python或PHP。这种形式可能是最易读的形式之一,但也存在其他形式,例如:

countNonNegatives xs = sum [1 | x <- xs, x >= 0]

答案 2 :(得分:1)

你有

filtering p cons x r = if | p x -> cons x r | otherwise -> r

countPositives = length 
                   . filter (> 0)
               = foldr (\x r -> r + 1) 0                              -- r++
                   . foldr (filtering (> 0) (:)            ) []
               =     foldr (filtering (> 0) (\x r -> r + 1))  0

(由于通过组合其变矩器来折叠 fuse ,a-la “ fold用reducer操作替换了缺点,因此,如果要替换,为什么要首先创建缺点无论如何” )和

filtering (> 0) (\x r -> r + 1) x r 
                     = if | (> 0) x -> (\x r -> r + 1) x r | otherwise -> r
                     = if | x > 0 -> r + 1 | otherwise -> r

,因此是您想要的具有 fold increment 的版本,

countPositives = foldr (\x r -> if | x > 0 -> r + 1 | otherwise -> r) 0  -- r++

您可以从这里拿走它。