2010-07-16 21 views
7

Tengo las siguientes dos funciones escritas.Par Haskell y funciones de desvinculación

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 

El par tomará pares de elementos y hará 2-tuplas de ellos. Si la lista tiene un número impar de elementos, descartar el último. Desvincular es el reverso del par.

Estos funcionan, pero se preguntan si hay una forma más concisa de escribirlos.

+5

Puede ser un poco prolijo, pero yo diría que gana sin esfuerzo en términos de claridad en comparación con las respuestas hasta el momento. (Sin ánimo de ofender a esos autores.) –

+0

Creo que la conclusión aquí es que una de cada dos funciones en las listas sería útil, ya que las personas gravitan hacia el enfoque zip. El paquete splits en Hackage tiene splitEvery que haría este estilo de solución más perspicuo. – Anthony

+0

Odio decirlo, pero a las alternativas que he visto hasta ahora: dije sucinta, no obtusa.:( – qrest

Respuesta

5

de una sola línea:

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

Usted podría tener también abreviar su definición de pair un poco:

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

No es más concisa, pero en aras de la claridad que haría uso splitEvery de Data.List.Split para pair:

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

Esto está fuera de mi cabeza, sería mejor comprobar únicamente la longitud de la última lista.

Para unpair que haría uso de foldr para evitar la recursión explícita:

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

Esto es sólo una cuestión de gusto.

+2

+1 para apoyar mi campaña en curso promoviendo el uso del nombre 'tuplify'. –

+0

' unpair = foldr (\\ (x, y) -> ([x, y] ++)) [] 'es más agradable imo –

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

Aunque definitivamente prefiero su definición de pair.

+1

Se nos ocurrió una solución casi idéntica :-) – sastanin

2

Tantas posibilidades. ¿Que tal esto?

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

Las dos versiones del par deben ser iguales.

Editar: En cuanto a mi comentario anterior, se puede utilizar el paquete de separación de Hackage escribir:

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

que está más cerca de la

deseada
pair xs = everyOther $ zip xs (tail xs) 

Pero, en el espíritu de inutilidad, Creo que probablemente todos deberíamos estar de acuerdo en escribirlo,

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

para asegurar confusión.

+0

Versión agradable con comprensión de listas. +1. – sastanin

1

Este es un uso agradable para 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

No creo que 'pair (splitAt 2 -> ([x, y], ys)) =' sea más legible que solo 'pair (x: y: ys) ='. – sastanin

+2

Pero eso no usa patrones de vista ... ':-)' –

Cuestiones relacionadas