Haskell配对和非配对功能

时间:2010-07-16 15:45:52

标签: haskell coding-style tuples

我写了以下两个函数。

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

Pair将采用成对的元素并制作它们的2元组。如果列表具有奇数个元素,则丢弃最后一个元素。 Unpair是对的反面。

这些工作,但想知道是否有更简洁的方法来编写这些。

5 个答案:

答案 0 :(得分:5)

一行程序:

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

您也可以将pair的定义略微缩写为:

pair (x1:x2:xs) = (x1, x2) : pair xs
pair _ = []

答案 1 :(得分:4)

它不再简洁,但为了清楚起见,我会使用splitEvery pair pair = map tuplify . filter ((>1) . length) . splitEvery 2 where tuplify [x, y] = (x, y)

unpair

这是我的头脑 - 只检查最后一个列表的长度会更好。

对于foldr,我使用unpair = foldr (\(x, y) -> (x:) . (y:)) [] 来避免显式递归:

{{1}}

这只是一个品味问题。

答案 2 :(得分:2)

有这么多可能性。这些怎么样?

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)]

对的两个版本应该是相同的。

编辑:关于我上面的评论,可以使用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)

以确保混淆。

答案 3 :(得分:1)

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的定义。

答案 4 :(得分:1)

这对view patterns非常有用:

{-# 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])