2015-03-22 20 views
6

Mam symulację z mnóstwem wywołań funkcji type F = A -> B -> C -> D, gdzie A .. D są konkretne typy. Obiekty o typie A mają średni czas życia. (To jest genom codegolf's ratrace.)Niezależne od siebie argumenty

Najdroższe obliczenia wynikają z parametru A. Mogę łatwo memoize tak:

f1 :: F 
f1 a = let expensive = trace "expensive computation!" $ expensiveComputation a 
     in \b c -> expensive 

i przytrzymać kilka wstępnie przetworzonych expensive wartości poprzez częściowego zastosowania:

preProz :: [B -> C -> D] 
preProz = [f1 [], f1 [False], f2 []] 

Ślady wskazują, że preProz <*> [[],[[]]] <*> [1,2] nie przeliczyć wartości do mojego zachwytu.

Teraz dowiedziałem się, że niektóre z moich F s również skorzystają z wstępnego przetwarzania B. To wstępne przetwarzanie jest niezależny z A, aw rzeczywistości memoizing jak to ma korzyści

f2 a = let expensive = trace "expensive computation!" $ expensiveComputation a 
     in \b -> let dear = trace "expensive computation!" $ expensiveComputation b 
        in expensive + dear 

ponieważ dear jest wyliczany, nawet jest b s równe.

Co potrzebne jest coś takiego:

(B -> e) -> A -> e -> C -> D 

gdzie e należy memoized. Typ e jest tutaj w pewnym sensie egzystencjalnym. Ale to zmusza mnie do przeliczenia wszystkich wartości A dla każdego B, który jest tak samo zły i nie mogę zapisać e s, które są prywatne dla funkcji.

Jak mogę niezależnie zapamiętać 2 parametry?

+4

Czy wstępne przetwarzanie A zależy od B lub odwrotnie? Jeśli wstępne przetwarzanie nie zależy od innych argumentów, to dlaczego nie po prostu przenieść go z funkcji: 'f1 <$> [procA a1, procA a2] <*> [procB b1, procB b2] <*> ...' Teraz wstępne przetwarzanie jest gwarantowane do uruchomienia tylko raz dla każdego argumentu. –

+0

Mam na myśli "przenieś go z funkcji". –

+0

"nie oblicza ponownie wartości jest [jak?] Przeznaczony" jest niejednoznacznym sformułowaniem: może to również oznaczać "Oczekiwano, że to się wyrejestruje, a nie" – chi

Odpowiedz

1

Trzeba funkcję memoizes zarówno a i b razem:

f12 a b = ... 
    in \c -> ... 

Gdy chcesz memoize a ale nie b, należy użyć f1 a i kiedy chcesz memoize zarówno użyć f12 a b.

Byłoby miło podzielić się pewną implementacją między f1 i f12. Jednak można to zrobić tylko poprzez prywatne funkcje, które zajmują się precomputed wyników w miejsce oryginalnych wartości:

f1 a = privateA (precomputeA a) 
f12 a b = privateAB (precomputeA a) (precomputeB b) 
privateA a' b = privateAB a' (precomputeB b) 
private AB a' b' c = ... 

Jeśli precomputation od b zależy precomputation z a, a następnie:

f1 a = privateA (precomputeA a) 
f12 a b = let a' = precomputeA a in privateAB a' (precomputeB a' b) 
privateA a' b = privateAB a' (precomputeB a' b) 
private AB a' b' c = ... 

Celowo nie użyłem składu funkcji i redukcji eta, aby wszystko było wyraźniejsze. Zostawiłem też adnotacje ścisłości, które mogą być przydatne do kontrolowania czasu oceny.

Być może pamiętanie nie jest tu właściwym pojęciem.Masz na myśli coś w rodzaju "częściowej aplikacji z pewnym precomputation".

Powiązane problemy