2010-05-27 40 views

Respuesta

39

De una manera general, no se puede. Cada tamaño de tupla es un tipo distinto, mientras que las listas de cualquier longitud son de un solo tipo. Por lo tanto, no hay una buena forma de escribir una función que tome una lista y devuelva una tupla de la misma longitud; no tendría un tipo de devolución bien definido.

Por ejemplo, usted podría tener funciones como:

tuplify2 :: [a] -> (a,a) 
tuplify2 [x,y] = (x,y) 

tuplify3 :: [a] -> (a,a,a) 
tuplify3 [x,y,z] = (x,y,z) 

... pero no uno que hace el trabajo de ambos.

puede escribir una versión genérica utilizando varios tipos de meta-programación, pero rara vez lo desea.

Tenga en cuenta que el mismo problema se aplica a otras cosas, como escribir instancias de clase para varias tuplas: ¡eche un vistazo a the source code for Data.Tuple de las bibliotecas estándar!

+0

¿Cómo puede ser esa la verdadera fuente de 'Data.Tuple'? Quiero decir ... el segundo elemento en la lista de exportación es: ', snd - :: (a, b) -> a'. ¿Este error evidente en los tipos está realmente allí? – Bakuriu

+2

@Bakuriu: Ja, es un error tipográfico divertido. Es solo un comentario, por supuesto, la firma de tipo en 'snd' cerca del final del archivo es correcta. Esa es también una versión bastante antigua de 'Data.Tuple', las versiones más recientes no tienen ese error. –

6

Tuplas y listas son cosas muy diferentes. Lo mejor que puede hacer es escribir manualmente una función de conversión:

toTuple :: [a] -> (a,a,a,a,a,a) 
toTuple [a,b,c,d,e,f] = (a,b,c,d,e,f) 

Aviso cómo diferentes los tipos son: la única variable de la lista se amplía a seis variables para la tupla. Entonces necesitarás una función para cada tamaño de tupla.

+1

Tú y Camccann me ganaron. Eso es todo, lo mejor que puede hacer son N funciones y luego un controlador para llamar a uno de estos para un N. – Spidey

+0

@Spidey dado: ¡o aprenda a usar Template Haskell! –

+0

Las tuplas son listas en matemáticas. ellos son muy similares. En la implementación de Haskell, las tuplas tienen una longitud de escritura fija y las listas no, por lo que no es fácil convertir las dos, pero ese es un problema de implementación específico del lenguaje. – clay

2

De hecho, puede hacer algo mejor que escribir manualmente una función por tuplo si usa cuasi-quotation [1]. Sin embargo, me pregunto acerca del código en el que espera usar esto genéricamente.

[1] http://www.haskell.org/haskellwiki/Quasiquotation

+0

Espero trabajar con un pequeño ejemplo más tarde cuando tenga tiempo y edite mi comentario con él ... – StevenC

+2

Cuasiquotación que forma parte de Template Haskell, creo, que es la metaprogramación a la que me refería. Al final, esto sigue produciendo una función por tamaño de tupla, solo está escribiendo código en tiempo de compilación para que lo haga por usted en lugar de escribirlo a mano. ¡Aún no me he acostumbrado a TH, así que espero ver tu ejemplo! –

+0

Edward Kmett me ganó. Pensé que lo había hecho con cuasiquotes antes, pero creo que solo era TH. Lo siento. – StevenC

23

Plantilla Haskell es lo más cerca que puede llegar debido a la comprobación de tipos si desea extraer un número variable de elementos, ya que (a, b) y (a, b, c) tener diferentes tipos

{-# LANGUAGE TemplateHaskell #-} 
import Language.Haskell.TH 
tuple :: Int -> ExpQ 
tuple n = do 
    ns <- replicateM n (newName "x") 
    lamE [foldr (\x y -> conP '(:) [varP x,y]) wildP ns] (tupE $ map varE ns) 

continuación:

$(tuple 6) [1,2,3,4,5,6] == (1,2,3,4,5,6) 
$(tuple 3) "abc" == ('a','b','c') 

Pero, en general, si necesita esta respuesta, entonces usted está haciendo la pregunta equivocada en alguna parte.

Si solo desea un acceso aleatorio plano, quizás la mejor opción sea utilizar una matriz.

+3

Plantilla Haskell es increíble, pero me gustaría que fuera un poco más legible. Por otra parte, tal vez es mejor que no lo sea, de lo contrario la gente lo usaría más de lo que realmente debería. –

+0

Aparentemente 'Control.Lens' se acerca aún más con' map (^ .. each) ', que también funciona para tuplas arbitrarias. - No es que nada que sea "para tuplas arbitrarias" tenga algo que ver con el objetivo de las tuplas. (Para eso están las listas. Las tuplas se usan precisamente cuando se quiere evitar este tipo de uso). – Evi1M4chine

+0

Debido a la forma en que 'cada uno 'usa patrones flojos: ' ghci> undefined & partsOf each. ~ [1,2, 3,4] :: (Int, Int, Int, Int) 'produce (1,2,3,4). Para que pueda ir en ambos sentidos hasta el tamaño 9 más o menos. Por supuesto, necesitas saber el tipo de tupla resultante. –

3

No creo que sea posible hacerlo en Haskell, para obtener una lista de longitud arbitraria desconocida en tiempo de compilación. La plantilla Haskell no puede hacerlo porque funciona solo en tiempo de compilación. Me encontré con un caso en el que necesitaba hacer precisamente esto, y tuve que evitarlo. Una biblioteca de base de datos espera tuplas de longitud diferente para argumentos de consulta, pero tengo una lista de longitud arbitraria. Así que tengo que rodear la interfaz de la biblioteca. Sería bueno si pudiera tomar una lista.

Básicamente, el problema es que las tuplas de diferentes longitudes son tipos diferentes. Pero el compilador Haskell debe saber en el tipo de compilación qué tipos pueden existir en el tiempo de ejecución. Convertir una lista de longitud arbitraria en una tupla en tiempo de ejecución podría crear algún tipo que no conocía en tiempo de compilación.

4

Me resulta difícil hacer explicaciones convincentes de manipulaciones Plantilla Haskell, pero aquí es una demostración:

> :m +Language.Haskell.TH 
> :set -XTemplateHaskell 
> runQ [| [1,2,3,4,5,6] |] >>= putStrLn . pprint 
[1, 2, 3, 4, 5, 6] 
> runQ [| [1,2,3,4,5,6] |] >>= \ (ListE exps) -> putStrLn (pprint (TupE exps)) 
(1, 2, 3, 4, 5, 6) 
8

Si siento como si estuviera a punto de aconsejar que apuntar con un arma a su pie y no confiar en usted para disparar.

> list2Tuple lst = read $ "(" ++ (init.tail.show) lst ++ ")" 
> list2Tuple [1,2,3] :: (Int, Int, Int) 
(1,2,3) 
> list2Tuple [1,2,3,4] :: (Int, Int, Int, Int) 
(1,2,3,4) 

Esto funcionará hasta la longitud de lo que cada vez tupla Show y de lectura se define para.

Cuestiones relacionadas