2010-09-18 22 views
7

Załóżmy, że chcę poznać wszystkie punkty na płaszczyźnie (x, y), które znajdują się w prostokącie has.Problem uogólniania Haskell (obejmujący rozumienie list)

mogę obliczyć, że przy użyciu wyrażeń listowych, w ten sposób:

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

Teraz, jeśli chcę osiągnąć to samo dla (x, y, z) przestrzeni, mogę pójść tą samą drogą i robić:

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

Czy istnieje sposób na uogólnienie tego dla dowolnej liczby wymiarów? Jeśli tak, w jaki sposób?

let myFunGeneralized = ? 

Dzięki

Odpowiedz

11

Niestety, z powodu [(a,a)] i [(a,a,a)] etc są różnych typów, nie można napisać jedną funkcję do reprezentowania wszystkich z nich.

Zresztą w ogóle można użyć

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

Jeśli chcesz [[a]] zamiast tego jest bardzo prosta funkcja to:

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

lub (dzięki sdcvvc)

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

Tak, jak istnieją przypadki równania zdefiniowane dla krotek do 15, nie powinno być tak trudno, aby twoja funkcja działała. – fuz

+0

@FUZxxl: Tak, ale wciąż trzeba napisać 15 różnych implementacji dla listy krotek. – kennytm

+0

Sekwencja jako operator permutacji: to takie eleganckie! –

1

Można użyć czegoś takiego:

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

Zostanie wyświetlona lista list punktów, można założyć, że wszystkie te podlisty mają tę samą długość. Powinno to działać tak:

> 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

Pierwsza implementacja zawierała błąd (zrobiłem' (dim, []) 'zamiast' (dim, [[]])) , ale teraz działa. – fuz

2

liście do krotka problemu mogłoby być traktowane z szablonu Haskell tak (uruchomiony 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)]