2012-12-17 10 views
19

Mi sembra che ci sia una forte connessione tra le due idee. La mia ipotesi è che il FRP potrebbe essere implementato in termini di Iteratees se ci fosse un modo per esprimere grafici arbitrari con Iteratees. Ma afaik supportano solo strutture a catena.Qual è la connessione tra Iteratees e FRP?

Qualcuno potrebbe far luce su questo?

risposta

13

È il contrario. Esiste una forte connessione tra AFRP e elaborazione del flusso. Infatti AFRP è una forma di stream processing, ed è possibile utilizzare l'idioma di implementare qualcosa di molto simile ai tubi:

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

Questo è un ampliamento delle categorie di filo come si trova in NetWire. Riceve il prossimo pezzo di input e restituisce Nothing quando smette di produrre. L'utilizzo di questo lettore un file potrebbe avere il seguente tipo:

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

Pipe è una famiglia di funtori applicativi, in modo da applicare una semplice funzione agli elementi del flusso si potrebbe utilizzare FMAP:

fmap (B.map toUpper) . readFile 

Per la vostra comodità è anche una famiglia di profunctors.

La caratteristica più interessante è che questa è una famiglia di funtori alternativi. Ciò consente di instradare i flussi e consentire a più processori stream di "provare" prima di rinunciare. Questo può essere esteso a una libreria di analisi completa che può persino utilizzare alcune informazioni statiche per scopi di ottimizzazione.

+0

Ah, stavo per pubblicare qualcosa di simile, ma rimanderò all'esperienza di qualcuno che in realtà ha scritto una libreria AFRP. :] –

+0

Sembra che usando (A) FRP non sarei limitato a una struttura di grafi aciclici, è vero? – fho

+3

Dalla mia risposta non mi è chiaro cosa succederebbe se alcuni aspetti dell'AFRP non fossero implementabili in termini o nel flusso recente in possesso di librerie conduit/pipe? – Davorak

13

È possibile implementare una forma limitata di FRP utilizzando processori di flusso. Ad esempio, utilizzando la libreria pipes, si potrebbe definire una fonte di eventi:

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

... e si potrebbe allo stesso modo definire un gestore grafico che prende coordinate del mouse e aggiorna un cursore su una tela:

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

Poi si sarebbe collegare gli eventi del mouse al gestore tramite composizione:

>>> runProxy $ mouseCoordinates >-> coordHandler 

e sarebbe eseguire solo il modo che ci si aspetta.

Come hai detto, questo funziona bene per una singola catena di fasi, ma per quanto riguarda le topologie più arbitrarie? Bene, dal momento che il tipo centrale Proxy di pipes è un trasformatore monad, è possibile modellare qualsiasi topologia arbitraria semplicemente annidando i trasformatori di monad proxy su se stessi. Ad esempio, ecco come si zip due flussi di ingresso:

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 

Questo comporta come una funzione di curry. Lo si applica parzialmente a ciascun input in modo sequenziale e quindi è possibile eseguirlo quando viene applicato completamente.

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

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

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

Funziona proprio come ci si aspetta:

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

Questo trucco generalizza a qualsiasi topologia.Puoi trovare molti più dettagli a riguardo in Control.Proxy.Tutorial nella sezione "Filiali, cerniere e fusioni". In particolare, dovresti dare un'occhiata al combinatore fork che usa come esempio, che ti permette di dividere un flusso in due uscite.

+0

Sono abbastanza sicuro che questo è vero per tutte le librerie iteratee sane. Oleg l'ha usato qualche tempo fa. Non sono sicuro del motivo per cui nessuno sembra mai ricordare che è possibile; la tecnica è molto utile. –

+0

@JohnL Ecco perché devi predicare! Non tutti sanno cosa ha fatto Oleg. –

+0

Anche le persone che sanno cosa Oleg ha fatto spesso non lo capiscono. Purtroppo sono spesso in questo gruppo, almeno all'inizio ... –

Problemi correlati