2010-09-18 16 views
7

Digamos que quiero saber todos los puntos en un plano (x, y) que están en el rectángulo has.Problema de generalización de Haskell (que involucra listas de comprensión)

puedo calcular que el uso de Listas por comprensión, de esta manera:

let myFun2D = [(x, y) | x <- [0..2], y <- [0..2]] 

Ahora, si yo quiero lograr lo mismo para un espacio (x, y, z), puedo seguir el mismo camino y hacer:

let myFun3D = [(x, y, z) | x <- [0..2], y <- [0..2], z <- [0..2]] 

¿Hay alguna forma de generalizar esto para cualquier cantidad de dimensiones? Si es así, ¿cómo?

let myFunGeneralized = ? 

Gracias

Respuesta

11

Desafortunadamente, debido [(a,a)] y [(a,a,a)] etc, son de diferentes tipos, no se puede escribir una función para representar a todos ellos.

De todos modos, en general, usted podría utilizar

Prelude> let x = [0..2] 
Prelude> import Control.Applicative 
Prelude Control.Applicative> (,,) <$> x <*> x <*> x 
[(0,0,0),(0,0,1),(0,0,2),(0,1,0),(0,1,1),(0,1,2),(0,2,0),(0,2,1),(0,2,2),(1,0,0),(1,0,1),(1,0,2),(1,1,0),(1,1,1),(1,1,2),(1,2,0),(1,2,1),(1,2,2),(2,0,0),(2,0,1),(2,0,2),(2,1,0),(2,1,1),(2,1,2),(2,2,0),(2,2,1),(2,2,2)] 

Si desea una [[a]] lugar, hay una función muy simple para esto:

Prelude> sequence (replicate 3 x) 
[[0,0,0],[0,0,1],[0,0,2],[0,1,0],[0,1,1],[0,1,2],[0,2,0],[0,2,1],[0,2,2],[1,0,0],[1,0,1],[1,0,2],[1,1,0],[1,1,1],[1,1,2],[1,2,0],[1,2,1],[1,2,2],[2,0,0],[2,0,1],[2,0,2],[2,1,0],[2,1,1],[2,1,2],[2,2,0],[2,2,1],[2,2,2]] 

o (sdcvvc gracias)

Prelude> import Control.Monad 
Prelude Control.Monad> replicateM 3 x 
[[0,0,0],[0,0,1],[0,0,2],[0,1,0],[0,1,1],[0,1,2],[0,2,0],[0,2,1],[0,2,2],[1,0,0],[1,0,1],[1,0,2],[1,1,0],[1,1,1],[1,1,2],[1,2,0],[1,2,1],[1,2,2],[2,0,0],[2,0,1],[2,0,2],[2,1,0],[2,1,1],[2,1,2],[2,2,0],[2,2,1],[2,2,2]] 
+0

Por lo tanto, ya que hay casos de la ecuación definidos para tuplas hasta 15, no debería ser tan difícil hacer que tu función funcione. – fuz

+0

@FUZxxl: Sí, pero todavía hay que escribir 15 implementaciones diferentes para la lista de tuplas. – kennytm

+0

Secuencia como operador de permutación: ¡eso es tan elegante! –

1

Puede usar algo como esto:

myFun :: Integer -> [[Integer]] -- Param: number of dimensions 
myFun dim = snd $ 
    until ((== 0) . fst) --recursive build your tuple 
    (\(d,lst) -> (pred d,[x:l|x <- [0..2],l <- lst])) 
    (dim,[[]]) 

Esto le dará una lista de listas de puntos, puede suponer que todas estas sublistas tienen la misma longitud. Se debe trabajar de esta manera:

> myFun 0 
    [] 
> myFun 1 
    [[0],[1],[2]] 
> myFun 2 
    [[0,0],[0,1],[0,2],[1,0],[1,1],[1,2],[2,0],[2,1],[2,2]] 
+0

La primera implementación contenía un error, (hice' (dim, []) 'en vez de' (dim, [[]]) ' , pero ahora funciona. – fuz

2

La lista de tupla problema podría ser manejado con Plantilla Haskell como esto (corriendo ghci -XTemplateHaskell):

> import Language.Haskell.TH 
> let x = [0..2] 
> let tt n l = listE [tupE [[|l!!i|] | i <- [0..(n-1)]] | l <- sequence $ replicate n l ] 
> $(tt 2 x) 
[(0,0),(0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2)] 
> $(tt 3 x) 
[(0,0,0),(0,0,1),(0,0,2),(0,1,0),(0,1,1),(0,1,2),(0,2,0),(0,2,1),(0,2,2),(1,0,0),(1,0,1),(1,0,2),(1,1,0),(1,1,1),(1,1,2),(1,2,0),(1,2,1),(1,2,2),(2,0,0),(2,0,1),(2,0,2),(2,1,0),(2,1,1),(2,1,2),(2,2,0),(2,2,1),(2,2,2)] 
Cuestiones relacionadas