Список разделов на основе конструктора данных - PullRequest
0 голосов
/ 02 мая 2018

Допустим, у меня есть следующее:

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 голосов
/ 02 мая 2018

Для этого вам не нужен раздел, просто левый сгиб:

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
0 голосов
/ 02 мая 2018

Это кажется выполнимым, если у вас все в порядке с тем, чтобы всегда иметь значение 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])
...