Является ли "список групп по размеру" сгибом?

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

> groupBy 3 [1..10] 
[[1,2,3], [4,5,6], [7,8,9], [10]]

ничего действительно трудного сделать, но сначала я был удивлен, что не смог найти для него функцию. Моя первая попытка была

 groupBy _ [] = []
 groupBy n xs = g : groupBy n gs
              where (g, gs) = splitAt n xs

до сих пор так хорошо, он работает, даже в бесконечном списке. Однако мне не нравится первая строка groupBy _ [] = []. Кажется, хороший кандидат для фолда, но я не мог понять этого.

так можно эту функцию можно записать как створка или как один лайнер ?

обновление

моя попытка одного лайнера:

groupBy' n l = map (map snd) $ groupBy ((==) `on` fst) $ concatMap (replicate n) [1..] `zip` l

мне потребовалось в 10 раз больше, чтобы написать, что первоначальная попытка.

обновление 2

после ответа Ганеша и использования unfoldr и pointfree Я вышел с этой запутанной точки свободного решения

groupBy' n = unfoldr $ listToMaybe . (ap (>>) (return.splitAt n))

1 ответов


вы можете сделать это как раза С некоторыми гимнастикой, но это гораздо лучше, как развернуть:

 unfoldr (\xs -> if null xs then Nothing else Just (splitAt n xs)) 

[вам нужно import Data.List Если вы еще не]

тип unfoldr - это:

unfoldr :: (b -> Maybe (a, b)) -> b -> [a]

идея unfoldr это формирование функция решает, следует ли остановить (Nothing) или продолжайте (Just). Если результат Just тогда первый элемент кортежа является следующим элемент списка вывода, а второй элемент снова передается в генерирующую функцию.

As @leftroundabout указано в комментарии к вопросу, разворачивание здесь гораздо более естественно, потому что оно рассматривает элементы выходного списка как похожие друг на друга, тогда как в сгибе элементы входного списка должны рассматриваться аналогично. В этом случае необходимо запустить новый подсписок every n элементы входного списка делают это сложнее.