如何在Haskell中递归递增元组?

时间:2016-01-09 15:46:03

标签: haskell tuples

我被要求创建一个函数来计算[Int]上的负数,零数和正数。然后应将结果写在元组(nrOfNeg,nrOfZeros,nrOfPos)上。

nzp [0,-1,1,2,0,3] =(1,2,3)

但是,列表必须只被覆盖一次(这意味着元组应该更新它在[Int]上评估的每个元素。)

类似的东西:

nzp [***0***,-1,1,2,0,3] = (0,1,0)
nzp [0,***-1***,1,2,0,3] = (1,1,0)
nzp [0,-1,***1***,2,0,3] = (1,1,1)
...

这是我到目前为止所做的,但它“使用”列表的3倍来计算。

nzp :: [Int] -> (Int,Int,Int)
nzp l = (neg,zeros,pos)
        where neg = length (filter (<0) l)
              zeros = length (filter (==0) l)
              pos = length (filter (>0) l)

在评估[Int]的元素时,有没有办法增加元组的特定位置?

3 个答案:

答案 0 :(得分:2)

无聊的方式

count :: (Num a, Ord a, Foldable f) => f a -> (Int, Int, Int)
count = foldl' go (0, 0, 0) where
  go (!neg, !zer, !pos) x =
    case compare x 0 of
      LT -> (neg + 1, zer, pos)
      EQ -> (neg, zer + 1, pos)
      GT -> (neg, zer, pos + 1)

有趣的方式

使用foldl

import qualified Control.Foldl as Fl
import Control.Lens.Fold

countF :: (a -> Bool) -> Fl.Fold a Int
countF p = Fl.handles (filtered p) Fl.length

count = Fl.fold ((,,) <$> countF (<0) <*> countF (==0) <*> countF (>0))

答案 1 :(得分:0)

你不能真正更新一个元组,因为值在Haskell中是不可变的。但是,您可以使用更新的值从上一个创建一个新的。提示,使用fold或简单的递归。

答案 2 :(得分:0)

这是foldl的一个很好的用例:

nzp :: [Int] -> (Int, Int, Int)
nzp = foldl accountForNumber (0, 0, 0)
      where accountForNumber (lt, eq, gt) x | x < 0 = (lt + 1, eq, gt)
            accountForNumber (lt, eq, gt) x | x > 0 = (lt, eq, gt + 1)
            accountForNumber (lt, eq, gt) _ | otherwise = (lt, eq + 1, gt)