2012-12-17 12 views
19

Wydaje mi się, że istnieje silny związek między tymi dwoma pomysłami. Domyślam się, że FRP może zostać wdrożone w kategoriach Iteratees, jeśli istnieje sposób na wyrażenie arbitralnych wykresów z Iteratees. Ale afaik wspierają tylko struktury łańcuchowe.Jaki jest związek między iteracjami i FRP?

Czy ktoś mógłby rzucić trochę światła na ten temat?

Odpowiedz

13

Jest odwrotnie. Istnieje silne połączenie między AFRP i przetwarzaniem strumienia. W rzeczywistości AFRP jest formą przetwarzania potokowego, można użyć idiomu zaimplementować coś bardzo podobnego do rur:

data Pipe m a b = 
    Pipe { 
     cleanup :: m(), 
     feed :: [a] -> m (Maybe [b], Pipe m a b) 
    } 

To rozszerzenie kategorii drutu, jak znaleźć w Netwire. Odbiera następny fragment danych wejściowych i zwraca Nic, gdy przestaje produkować. Korzystanie z tego czytelnikowi pliku miałby następujące rodzaje:

readFile :: (MonadIO m) => FilePath -> Pipe m a ByteString 

rura jest rodzina aplikacyjnych funktorów, tak aby zastosować prostą funkcję do elementów strumienia można po prostu użyć FMap:

fmap (B.map toUpper) . readFile 

Dla Twojej wygody jest to także rodzina profunktorów.

Najbardziej interesującą cechą jest to, że jest to rodzina alternatywnych funktorów. To pozwala na kierowanie strumieni wokół i pozwala wielu procesorom strumieniowym "wypróbować" przed poddaniem się. Może to zostać rozszerzone na pełnoprawną bibliotekę analizowania, która może nawet wykorzystywać pewne statyczne informacje do celów optymalizacji.

+0

Ah, miałem zamiar opublikować coś podobnego, ale odłożę się na wiedzę kogoś, kto faktycznie napisał bibliotekę AFRP. :] –

+0

Wygląda na to, że użycie (A) FRP nie ogranicza się do struktury wykresu acyklicznego, czy to prawda? – fho

+3

Nie jest dla mnie jasne z twojej odpowiedzi, czy jakikolwiek aspekt AFRP nie może być zaimplementowany w terminach lub w ostatnim strumieniu posiadającym biblioteki kanałów/rur? – Davorak

13

Możesz zaimplementować ograniczoną formę FRP przy użyciu procesorów strumieniowych. Na przykład, przy użyciu biblioteki pipes, można zdefiniować źródło zdarzeń:

mouseCoordinates :: (Proxy p) =>() -> Producer p MouseCoord IO r 

... i można podobnie zdefiniować graficzną obsługi, która pobiera i aktualizuje współrzędne myszy kursor na płótnie:

coordHandler :: (Proxy p) =>() -> Consumer p MouseCoord IO r 

Następnie należy podłączyć zdarzeń myszy do obsługi za pomocą składzie:

>>> runProxy $ mouseCoordinates >-> coordHandler 

I będzie działać tak, jak można się spodziewać.

Tak jak powiedziałeś, działa to dobrze dla pojedynczego łańcucha etapów, ale co z bardziej arbitralnymi topologiami? Okazuje się, że skoro centralny pipes jest monadowym transformatorem, można modelować dowolną topologię, po prostu zagnieżdżając transformatory monad proxy na sobie. Na przykład, oto, w jaki sposób można zamieniać dwa strumienie wejściowe:

zipD 
:: (Monad m, Proxy p1, Proxy p2, Proxy p3) 
=>() -> Consumer p1 a (Consumer p2 b (Producer p3 (a, b) m)) r 
zipD() = runIdentityP $ hoist (runIdentityP . hoist runIdentityP) $ forever $ do 
    a <- request()    -- Request from the outer Consumer 
    b <- lift $ request()  -- Request from the inner consumer 
    lift $ lift $ respond (a, b) -- Respond to the Producer 

Zachowuje się jak funkcja curry. Częściowo stosuje się go do każdego wejścia sekwencyjnie, a następnie można go uruchomić po pełnym zastosowaniu.

-- 1st application 
p1 = runProxyK $ zipD <-< fromListS [1..] 

-- 2nd application 
p2 = runProxyK $ p2  <-< fromListS [4..6] 

-- 3rd application 
p3 = runProxy $ printD <-< p3 

To działa dokładnie tak, jak można się spodziewać:

>>> p3 
(1, 4) 
(2, 5) 
(3, 6) 

Ta sztuczka uogólnia do dowolnej topologii.Więcej informacji na ten temat można znaleźć w sekcji Control.Proxy.Tutorial w sekcji "Oddziały, zamki i scalenia". W szczególności powinieneś sprawdzić kombinator fork, którego używa jako przykładu, który pozwala podzielić strumień na dwa wyjścia.

+0

Jestem prawie pewien, że jest to prawda ze wszystkich zdrowych bibliotek iteratee. Oleg użył go jakiś czas temu. Nie jestem pewien, dlaczego nikt nigdy nie pamięta, że ​​jest to możliwe; technika jest bardzo przydatna. –

+0

@JohnL Dlatego musisz go głosić! Nie wszyscy wiedzą, co zrobił Oleg. –

+0

Nawet ludzie, którzy wiedzą, co Oleg często nie rozumieją. Niestety często jestem w tej grupie, przynajmniej na początku ... –

Powiązane problemy