Próbuję znaleźć sposób na przetłumaczenie normalnej notacji rekurencyjnej, takiej jak jako | fib | funkcja poniżej do strzałki, zachowując jak najwięcej struktury zapisu rekursywnego. Ponadto chciałbym jak sprawdzić strzałkę. Do tego utworzone typ danych zawierającą dla każdego konstruktora Strzałka {..} klasy:Obserwowalna rekursja (lub wiązanie) w strzałkach
Fib:
fib 0 = 0
fib 1 = 1
fib n = fib (n-2) + fib (n-1)
My R typu danych, przypadki dla tego typu danych składa się z mapowania do odpowiedniego konstruktora :
data R x y where
-- Category
Id :: R a a
Comp :: R b c -> R a b -> R a c
-- Arrow
Arr :: (a -> b) -> R a b
Split :: R b c -> R b' c' -> R (b,b') (c,c')
Cache :: (a -> a -> Bool) -> R a a
-- ArrowChoice
Choice :: R b c -> R b' c' -> R (Either b b') (Either c c')
-- ArrowLoop
Loop :: R (b, d) (c, d) -> R b c
-- ArrowApply
Apply :: R (R b c, b) c
Tłumaczenie | fib | funkcja z powyższego skutkuje najpierw następującą definicją: . Nie jest to jednak dozwolone ze względu na proklamację RHS deklaracji dla | fibz |. Wiem, że gramatyka zapisywania strzałek zapobiega temu, ale co to jest podstawowy powód?
fib' :: (ArrowChoice r, ArrowLoop r) => r Int Int
fib' = proc x -> do
rec fibz <- proc n -> case n of
0 -> returnA -< 0
1 -> returnA -< 1
n' -> do l <- fibz -< (n'-2)
r <- fibz -< (n'-1)
returnA -< (l+r)
fibz -<< x
Przepisanie powyższej funkcji w celu użycia kompilacji let. Jednak tutaj pojawia się mój drugi problem: . Chcę móc sprawdzić rekurencję, w której się znajduje. Jednak w tym przypadku | fibz | to nieskończone drzewo . Chciałbym uchwycić rekursję do fibz, I nadzieję, że rec pomoże mi w połączeniu z pętlą | ale może się mylę?
fib'' :: (ArrowChoice r, ArrowLoop r, ArrowApply r) => r Int Int
fib'' = proc x -> do
let fibz = proc n -> case n of
0 -> returnA -< 0
1 -> returnA -< 1
n' -> do l <- fibz -< (n'-2)
r <- fibz -< (n'-1)
returnA -< (l+r)
fibz -<< x
Zasadniczo, czy można zaobserwować ten rodzaj rekurencji? (Być może nawet w granicach Notacji Strzał) mógłbym dodać innego konstruktora takiego jak fix. Może powinienem być w stanie obserwować wiązanie zmiennych, aby odnoszenie się do nich stało się możliwe. To jednak wykracza poza zakres Arrows.
Jakieś przemyślenia na ten temat?
Aktualizacja 1: Wymyślam ten formularz poza spisem strzałki. To ukrywa rekursję wewnątrz app
i dlatego kończę z skończoną reprezentacją Strzałki. Nadal jednak chcę mieć możliwość np. zamień wywołanie na fib
wewnątrz app
na zoptymalizowaną wersję fib
.
fib :: (ArrowChoice r, ArrowLoop r, ArrowApply r) => r Int Int
fib
= (arr
(\ n ->
case n of
0 -> Left()
1 -> Right (Left())
n' -> Right (Right n'))
>>>
(arr (\() -> 0) |||
(arr (\() -> 1) |||
(arr (\ n' -> (n', n')) >>>
(first (arr (\ n' -> app (fib, n' - 2))) >>>
arr (\ (l, n') -> (n', l)))
>>>
(first (arr (\ n' -> app (fib, n' - 1))) >>>
arr (\ (r, l) -> (l + r)))))))
Ten kod odpowiada z następujących w notacji strzałka:
fib :: (ArrowChoice r, ArrowLoop r, ArrowApply r) => r Int Int
fib = proc n ->
case n of
0 -> returnA -< 0
1 -> returnA -< 1
n' ->
do l <- fib -<< (n'-2)
r <- fib -<< (n'-1)
returnA -< (l+r)
Jak napisałbyś "fib" pod względem 'R'? –
@SjoerdVisscher Zaktualizowałem pytanie, aby dołączyć "fib" pod względem 'R'. (ale przy użyciu metod klasy) –
W [reddit] trwa dyskusja (http://www.reddit.com/r/haskell/comments/11ayds/observable_recursion_in_arrows/). –