2013-06-23 17 views
5

Diciamo che hoCome trasformare eventi con una funzione IO?

e1 :: Event t A 
f :: A -> IO B 

voglio creare

e2 :: Event t B 

che viene innescato da e1, ei cui valori sono determinati eseguendo f sul valore del e1 al momento del verificarsi dell'evento .

Vedo due modi potenziali per farlo, tramite la commutazione dinamica degli eventi e l'utilizzo di gestori, ma entrambi sembrano troppo complicati per una cosa così semplice.

Qual è il modo corretto per farlo?

+0

è un'opzione 'unsafePerformIO'? – Ankur

+1

@Ankur: no, non è sicuramente un "modo corretto". –

risposta

2

Poiché la funzione f ha un effetto collaterale, questa non è in realtà una cosa semplice da fare. Il motivo principale è che l'ordine degli effetti collaterali non è ben definito quando ci sono più eventi simultanei. Più in generale, non ero in grado di concepire una buona semantica per trattare le azioni IO negli eventi. Di conseguenza, la banana reattiva non fornisce un combinatore puro per questa situazione.

Se si desidera comunque fare ciò, è necessario utilizzare un meccanismo più elaborato che determina anche l'ordine degli effetti collaterali. Per esempio, è possibile utilizzare reactimate e scrivere un combinatore

mapIO :: Frameworks t => (a -> IO b) -> Event t a -> Moment t (Event t b) 
mapIO f e1 = do 
    (e2, fire2) <- liftIO newAddHandler 
    reactimate $ (\x -> f x >>= fire2) <$> e1 
    fromAddHandler e2 

Tuttavia, si noti che questo può dare risultati inattesi come l'evento result e2 non è più contemporanea con l'evento di ingresso e1. Ad esempio, i comportamenti potrebbero essere cambiati e altri effetti collaterali potrebbero essere stati eseguiti.

+1

È un po 'sorprendente, dato che l'intero scopo di FRP è di occuparsi di IO, che le azioni IO non sono "di prima classe". In particolare, gli eventi simultanei hanno ordinamento - quindi perché non utilizzare lo stesso ordinamento per gli effetti corrispondenti? Capisco che questo non è a prova di proiettile - ad es. un'azione IO può attivare altri eventi o richiedere troppo tempo per considerare gli eventi come "simultanei" ... Ma posso assumermi una responsabilità in tal senso; cioè, prometto di non invocare alcun gestore di eventi e l'azione sarà "istantanea" per i miei scopi. È ancora impossibile? Perché? –

+1

Bene, gli eventi simultanei possono avere un ordinamento in ogni evento, ma non esiste un ordinamento globale. Considera i due eventi 'union ex ey' e' union ey ex' dove 'ex' e' ey' hanno occorrenze simultanee. Un programma può utilizzare felicemente entrambe le combinazioni allo stesso tempo, ma l'ordine delle occorrenze simultanee degli eventi sarà diverso per ciascuna. Più in generale, non sono riuscito a trovare una buona semantica per ordinare azioni IO negli eventi, quindi reattiva, la banana non li supporta. (Ho aggiornato la mia risposta per enfatizzare questo punto.) –

+2

Per quanto riguarda FRP in generale, spero che questo non sia una delusione, ma l'attenzione è sul calcolo con eventi e valori variabili nel tempo e non tanto su IO. Detto questo, è spesso necessario interfacciarsi con IO al limite e ci sono molte possibilità: 'reactimate', o il combinatore' mapIO' qui presentato, o il combinatore 'mapIO' nel' Reactive.Banana.Frameworks.Modulo AddHandler' che può essere utilizzato per modificare gli eventi prima di passarli al mondo FRP. –

1

È possibile chiamare la funzione f in reactimate (che per quanto ho capito è il "modo corretto" per gestire l'I/O dalla rete eventi)? Da lì, attivare un nuovo evento di tipo Event t B nella rete degli eventi. O è questo che intendevi per "usare gli handler"?

+0

Sì, questo è ciò che intendo per "usare gestori". –

Problemi correlati