基于数据构造函数的分区列表

时间:2018-05-02 18:36:49

标签: haskell partition

我们说我有以下内容:

data D = A Int | B Int deriving Show

我有一个功能

simplify :: [D] -> [D]

我的目标是简化创建新列表,将所有值与数据A相加(合并为单个数据值A),并将B数据保存为是

例如,[A 1, A 2, A 3, B 1, A 4, B 2]将成为[A 10, B 1, B 2]

我知道我可以用foldl做到这一点:

A (foldl (+) 0 [x | A x <- ll]) : [B x | B x <- ll]

但这涉及到两次寻找构造函数的列表。 我想知道是否有一种使用分区的方法,我可以将列表分成具有数据A的那些和不具有数据的那些。

2 个答案:

答案 0 :(得分:3)

如果您在A之前始终具有B值,那么这似乎是可行的。

simplify :: [D] -> [D]
simplify = uncurry (:) . foldr f (A 0, [])
  where
  f (A x) ((A n), acc) = (A (n+x),   acc)
  f b     (a    , acc) = (a      , b:acc)

虽然老实说我认为uncurry (:)在这里是个错误,你的最终类型应该是:

simplify :: [D] -> (D, [D])

答案 1 :(得分:1)

您不需要分区,只需左侧折叠:

import Data.List (mapAccumL)

simplify :: [D] -> [D]
simplify = f . mapAccumL g 0 
  where
  g acc (A i) = acc `seq` (acc+i, [])
  g acc b     = (acc,  [b])
  f (acc, ys) = A acc : concat ys