2012-04-12 21 views
9

Chciałbym wygenerować dość duży, ale skończony, kartezjański produkt w Haskell, który muszę następnie iterować (myślę, że funkcja podziału na model pola średniego). Naturalną rzeczą do zrobienia używa sequence coś takiego:Leniwy produkt kartezjański w Haskell

l = sequence $ replicate n [0,1,2] 

Niestety, dla dużej n, to nie mieści się w pamięci i biegnę z hałdy, jak tylko poprosić o length l na przykład. Potrzebowałabym sposobu, żeby leniwie zrobić to samo. Skończyło się „odkrywając” Base-3 arytmetyki, tak,

nextConfig []  = [] 
nextConfig (0:xs) = 1:xs 
nextConfig (1:xs) = 2:xs 
nextConfig (2:xs) = 0:(nextConfig xs) 

ll = take (3^n) $ iterate nextConfig $ replicate n 0 

(które działa), ale wydaje się, jakby odkrywanie koła na nowo, a poza tym to jest zbyt szczegółowe. Jaki byłby lepszy leniwy sposób generowania produktu?

+0

Czy zależy Ci na kolejności elementów w wyniku? – augustss

+0

Nie, o ile nie ma powtórzeń. –

+0

Jak duże jest 'n'? – dave4420

Odpowiedz

5

Im więcej pamięci przyjazny sposób uzyskuje się poprzez wiązanie się w odwrotnej kolejności w stosunku do sekwencji,

foo 0 _ = [[]] 
foo k xs = [h:t | t <- foo (k-1) xs, h <- xs] 

Jest wolniej ze względu na mniejsze dzielenia się, ale ponieważ pamięć jest twój problem, może to wystarczająco dobre dla ciebie.

+0

Super! Będę musiał zbadać więcej, dlaczego to działa, ale na pewno tak. Zmodyfikowałem go jako 'foo (l: ls) = [h: t | t <- foo2 ls, h <- l] '(kto wie, czy zawsze będę potrzebował kostki) i działa również. Dzięki! –

+0

Dlaczego obsługa list jest bardziej wydajna niż notacja do list (która jest używana w 'sekwencji')? Widzę z raportu Haskell2010, że oba są desugar do 'concatMap'? – haskelline

+2

@brence: Zobacz odpowiedź Duncana Couttsa na to czerwone pytanie: [Dlaczego strażnicy na liście znajdują się szybciej niż w notacji?] (Http://www.reddit.com/r/haskell/comments/oolyt/why_are_guards_in_the_list_comprehension_faster /) – danr

Powiązane problemy