2010-07-16 9 views
7

J'ai les deux fonctions suivantes écrites.Fonction Haskell et fonctions de désassemblage

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 

La paire prendra des paires d'éléments et en fabriquera 2-tuples. Si la liste contient un nombre impair d'éléments, ignorez le dernier. Unpair est l'inverse de la paire.

Ceux-ci fonctionnent, mais se demandent s'il existe une façon plus succincte de les écrire.

+5

Il est peut-être un peu bavard, mais je dirais qu'il gagne haut la main en termes de clarté par rapport aux réponses à ce jour. (Sans vouloir offenser ces auteurs.) –

+0

Je pense que le point à retenir ici est qu'une fonction eachOther sur les listes serait utile puisque les gens gravitent vers l'approche zip. Le paquet splits sur Hackage a splitEvery qui rendrait ce style de solution plus perspicace. – Anthony

+0

Haine de le dire, mais pour les alternatives que j'ai vu jusqu'à présent: je l'ai dit succinct, pas obtus.:( – qrest

Répondre

5

one-liners:

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

Vous pouvez également abrégez votre définition de pair un peu:

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

Ce n'est pas plus concise, mais par souci de clarté j'utiliser splitEvery de Data.List.Split pour pair:

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

Cela me dépasse: il serait plus agréable de vérifier la longueur de la dernière liste seulement.

Pour unpair j'utiliser foldr pour éviter la récursion explicite:

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

Ceci est juste une question de goût.

+2

+1 pour soutenir ma campagne en cours promouvant l'utilisation du nom «tuplify» –

+0

'unpair = foldr (\\ (x, y) -> ([x, y] ++)) []' est plus agréable –

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

Bien que je préfère nettement votre définition de pair.

+1

Nous sommes venus avec des solutions presque identiques :-) – sastanin

2

Autant de possibilités. Que penses-tu de ceux-ci?

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

Les deux versions de paire doivent être identiques.

Edit: En ce qui concerne mon commentaire ci-dessus, on peut utiliser le package split de Hackage écrire:

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

qui est plus proche du choix

pair xs = everyOther $ zip xs (tail xs) 

Mais, dans l'esprit de futilité, Je pense que nous devrions probablement tous d'accord sur l'écriture,

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

pour assurer la confusion.

+0

Belle version avec compréhension de la liste. +1 – sastanin

1

C'est une belle utilisation pour 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]) 
+0

Je ne pense pas que 'pair (splitAt 2 -> ([x, y], ys)) =' est plus lisible que juste paire (x: y: ys) = '. – sastanin

+2

Mais cela n'utilise pas les modèles de vue ... ':-)' –