2012-03-18 13 views
6

Wyobraź sobie, że musisz złożyć sekwencję i chcesz poznać również wartości pośrednie w kilku punktach wzdłuż tego zakresu. To właśnie użyłem do tego:Jaki jest ten wzór składania i iteracji?

[a,b,c] = map fst . tail $ chain [g i, g j, g k] (zero, sequence) 

g :: Integer -> (a,b) -> (a,b) 

chain (f:fs) x = x : chain fs (f x) 
chain [] x = [x] 

Funkcja g zużywa określoną część sekwencji wejściowej (długości i, j, etc.), począwszy od początkowych wartości i produkujących takie same wyniki typ, który zostanie wprowadzony do następnej inwokacji. Zużywanie sekwencji kilkukrotnie dla różnych długości, począwszy od początku i tej samej wartości początkowej, byłoby nieefektywne, zarówno w czasie, jak i w przestrzeni.

Tak więc z jednej strony składamy tę sekwencję liczb całkowitych - punkty pośrednie w sekwencji; z drugiej strony, iterujemy tę funkcję, g. Co to jest? Czy tu brakuje czegoś podstawowego? Czy można to w jakiś sposób wyrazić za pomocą regularnego repertuaru fałd itp.?

EDIT:   Rozwiązany:   powyższe jest po prostu

[a,b,c] = map fst . tail $ scanl (flip g) (zero, sequence) [i, j, k] 

ciekawy jak modyfikowalne iteracja faktycznie jest składane na liście modyfikatorów.

+6

Czy w zasadzie oznaczasz skaner? http://www.haskell.org/hoogle/?hoogle=scanl – Marcin

+1

@Marcin ah, tak, podstawowe rzeczy. Prawdopodobnie tak. Tym, co mnie zmyliło, było to, że samo "g" również składa się na sekwencję. Domyślam się, że funkcja skanowania łączyłaby '(zero, sekwencja)' z 'i' i skanowała bezpośrednio' [i, j, k] '... Dzięki, spróbuje! –

Odpowiedz

9

Spróbuj scanl: http://www.haskell.org/hoogle/?hoogle=scanl

scanl jest podobna do foldl, ale zwraca listę kolejnych obniżonych wartości od lewej:

scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...] 

Zauważ, że

last (scanl f z xs) == foldl f z xs 
4

Aby opracować na Komentarz Marcina, w zasadzie chcą:

intermediates = scanl step zero sequence 
map (\n -> intermediates !! n) [i, j, k] 

step nie jest g, ale raczej tylko część g że zużywa pojedynczy element listy sequence.

Zaakceptuj także Marcina jako poprawną odpowiedź.

+0

sama sekwencja jest ogromna (no, * duża *), a potrzebuję tylko dwóch półproduktów i jednego finału. Wszystko to ma zmniejszyć zużycie przestrzeni i dać ghc szansę na pozbycie się jak największej ilości rzeczy. Ponadto zaakceptowałem 5 minut przed Twoim postem. :) Dzięki! –

+0

Jeśli skompilujesz powyższe z optymalizacjami GHC powinien automatycznie usuwać zbędne wyniki pośrednie, których nie używasz, więc powinien działać w stałej przestrzeni. To nie jest droższe niż w przypadku ręcznego złożenia ręcznie. –

+0

Mam podejrzenie, że '(!! n)' będzie wymagało istnienia całej sekwencji, ponieważ musi zacząć odliczanie od początku. Ale spróbuję później, dzięki.Każda poprzednia wartość jest potrzebna do wyprodukowania następnej; nawet jeśli nie jest już potrzebna, to jest dużo aktywności (gc), a sama lista nadal będzie utrzymywana, więc może nawet nie uwolnić wartości każdego węzła, ponieważ była już wymuszona. Przy obliczaniu według kroków, których dokładnie uniknięto, miejmy nadzieję. Rzeczywiście zauważyłem znaczny spadek wielkości przestrzeni z moim podejściem. –