2013-06-23 18 views
5

Powiedzmy mamJak przekształcać zdarzenia za pomocą funkcji IO?

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

Chcę utworzyć

e2 :: Event t B 

który jest wyzwalany przez e1, i których wartości są określane przez wykonanie f od wartości e1 w momencie wystąpienia zdarzenia .

Widzę dwa potencjalne sposoby, aby to zrobić, poprzez dynamiczne przełączanie zdarzeń i używanie procedur obsługi, ale oba wydają się zbyt skomplikowane dla tak prostej rzeczy.

Jaki jest właściwy sposób na zrobienie tego?

+0

to opcja "unsafePerformIO"? – Ankur

+1

@Ankur: nie, to zdecydowanie nie jest "właściwa droga". –

Odpowiedz

2

Ponieważ funkcja f ma efekt uboczny, w rzeczywistości nie jest to proste. Głównym powodem jest to, że kolejność efektów ubocznych nie jest dobrze zdefiniowana, gdy występuje wiele jednoczesnych zdarzeń. Ogólnie rzecz biorąc, nie byłem w stanie wyobrazić sobie dobrej semantyki do radzenia sobie z działaniami IO w wydarzeniach. W konsekwencji, reaktywny-banan nie zapewnia czystego kombinatora dla tej sytuacji.

Jeśli jednak chcesz to zrobić, musisz użyć bardziej rozbudowanego mechanizmu, który określa kolejność efektów ubocznych. Na przykład, można użyć reactimate i napisać COMBINATOR

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 

Należy jednak pamiętać, że może to dać nieoczekiwane rezultaty w przypadku wyników e2 nie jest już równoczesny ze zdarzeniem wejściowym e1. Na przykład zachowanie mogło się zmienić i inne efekty uboczne mogły zostać wykonane.

+1

To trochę zaskakujące, biorąc pod uwagę, że głównym celem FRP jest radzenie sobie z IO, że działania IO nie są "pierwszorzędne". W szczególności, zdarzenia jednoczesne mają kolejność - więc dlaczego nie zastosować tej samej kolejności dla odpowiednich efektów? Rozumiem, że nie jest to punktor kuloodporny - np. działanie IO może wywoływać inne zdarzenia lub poświęcać zbyt dużo czasu na postrzeganie wydarzeń jako "równoczesne" ... Ale mogę wziąć za to odpowiedzialność; to znaczy, obiecuję nie wywoływać żadnych programów obsługi zdarzeń, a akcja będzie "natychmiastowa" dla moich celów. Czy to wciąż niemożliwe? Czemu? –

+1

Cóż, zdarzenia jednoczesne mogą mieć porządek w każdym wydarzeniu, ale nie ma globalnego porządku. Rozważ dwa zdarzenia "union ex ey" i "union ey ex", gdzie 'ex' i' ey' mają jednoczesne wystąpienia. Program może z powodzeniem używać obu kombinacji w tym samym czasie, ale kolejność jednoczesnych wystąpień zdarzeń będzie różna dla każdego z nich. Ogólnie rzecz biorąc, nie mogłem znaleźć dobrej semantyki do zamawiania akcji IO w zdarzeniach, dlatego reaktywny-banan ich nie obsługuje. (Zaktualizowałem swoją odpowiedź, aby podkreślić tę kwestię). –

+2

W odniesieniu do ogólnie przyjętej oferty FRP, mam nadzieję, że nie jest to rozczarowanie, ale nacisk kładziony jest na obliczanie za pomocą zdarzeń i wartości zmiennych w czasie, a nie na IO. To powiedziawszy, często musisz łączyć się z IO na granicy i istnieje wiele możliwości: 'reactate' lub kombinator' mapIO' przedstawiony tutaj lub kombinator 'mapIO' w' Reactive.Banana.Frameworks.Moduł AddHandler', który może być używany do modyfikowania zdarzeń przed przekazaniem ich do świata FRP. –

1

Czy można wywołać funkcję f w reactimate (która, o ile rozumiem, jest "właściwą metodą" do obsługi IO z sieci zdarzeń)? Następnie wystrzel nowe zdarzenie typu Event t B do sieci zdarzeń. A może chodziło Ci o "używanie funkcji obsługi"?

+0

Tak, właśnie przez to rozumiem "używanie modułów obsługi". –

Powiązane problemy