Пара Haskell и непарные функции

У меня есть следующие две записанные функции.

pair :: [a] -> [(a, a)]
pair [] = []
pair [x] = []
pair (x1:x2:xs) = (x1, x2) : pair xs

unpair :: [(a, a)] -> [a]
unpair [] = []
unpair ((x1, x2):xs) = x1 : x2 : unpair xs

Пара возьмет пар элементов и сделает 2 кортежа из них. Если список имеет нечетное число элементов, отбросьте последний. Непара является реверсом пары.

Они работают, но задающийся вопросом, существует ли более сжатый способ записать их.

7
задан Don Stewart 20 April 2011 в 22:51
поделиться

5 ответов

One-liners:

pair xs = map snd . filter fst . zip (iterate not True) $ zip xs (drop 1 xs)
unpair = concatMap (\(x,y) -> [x,y])

Вы могли бы также немного сократить ваше определение пары:

pair (x1:x2:xs) = (x1, x2) : pair xs
pair _ = []
5
ответ дан 6 December 2019 в 19:32
поделиться

Оно не более лаконичное, но для ясности я бы использовал splitEvery из Data.List.Split for pair:

pair = map tuplify . filter ((>1) . length) . splitEvery 2
  where
    tuplify [x, y] = (x, y)

Это с головы - было бы приятнее проверять длину только последнего списка.

Для unpair я бы использовал foldr, чтобы избежать явной рекурсии:

unpair = foldr (\(x, y) -> (x:) . (y:)) []

Это просто дело вкуса.

4
ответ дан 6 December 2019 в 19:32
поделиться
pair s = dropEven $ zip s (tail s)
     where dropEven s = map fst $ filter snd $ zip s (cycle [True, False])

unpair = concatMap (\(a, b) -> [a, b])

Хотя я определенно предпочитаю ваше определение pair.

1
ответ дан 6 December 2019 в 19:32
поделиться

Это хорошее применение для шаблонов представления :

{-# LANGUAGE ViewPatterns #-}

pair :: [a] -> [(a,a)]
pair (splitAt 2 -> ([x,y],ys)) = (x,y) : pair ys
pair _ = []

unpair :: [(a,a)] -> [a]
unpair = (>>= \(x,y) -> [x,y])
1
ответ дан 6 December 2019 в 19:32
поделиться

Так много возможностей. Как насчет этого?

unpair' = concatMap (\(x,y) -> [x,y])
pair' xs = map snd . filter fst . zip (cycle [True, False]) $ zip xs (tail xs)
pair'' xs = [(x,y) | (True,x,y) <- zip3 (cycle [True,False]) xs (tail xs)]

Две версии пары должны быть одинаковыми.

Edit: Что касается моего комментария выше, можно использовать разделенный пакет от Hackage, чтобы написать:

pair xs = map head . splitEvery 2 $ zip xs (tail xs)

что ближе к желаемому

pair xs = everyOther $ zip xs (tail xs)

Но, в духе бессмысленности, я думаю, что мы, вероятно, все должны согласиться на написание это,

pair = map head . splitEvery 2 . (zip <$> id <*> tail)

, чтобы избежать путаницы.

2
ответ дан 6 December 2019 в 19:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: