2013-01-10 9 views
15

Podczas wykonywania akcji zamówienia reklamowego zdefiniowanej przez someFun <$> (a :: IO()) <$> (b :: IO()), jest wykonywane wykonanie akcji a i b? To znaczy, czy mogę liczyć na to, że a jest wykonywane przed b?Haskell - Czy deterministyczny porządek efektów w przypadku Wnioskodawcy?

Dla GHC, widzę IO zaimplementowane przy użyciu stanu, a także zobacz here, że jest to instancja aplikacji, ale nie może znaleźć źródła deklaracji rzeczywistej instancji. Implementacja za pośrednictwem państwa sugeruje, że różne efekty IO muszą być sekwencyjne, ale nie jest konieczne określenie ich kolejności.

Zabawa w GHCi wydaje się, że Appliative zachowuje kolejność efektów, ale czy jest to jakaś gwarancja uniwersalna, czy GHC specyficzna? Byłbym zainteresowany szczegółami.

import System.Time 
import Control.Concurrent 
import Data.Traversable 
let prec (TOD a b) = b 
fmap (map prec) (sequenceA $ replicate 5 (threadDelay 1000 >> getClockTime)) 

[641934000000,642934000000,643934000000,644934000000,645934000000] 

Dzięki!

+0

Zgaduję, że ten wpis zawiera przydatne informacje, ale muszę je jeszcze przetrawić: http://pchiusano.blogspot.hu/2011/07/do-side-effects-really-need-total-order.html – ron

+4

Zobacz http : //hackage.haskell.org/packages/archive/transformers/0.3.0.0/doc/html/Control-Applicative-Backwards.html, który jest transformatorem aplikacyjnym odwracającym kolejność efektów. –

Odpowiedz

18

To na pewno deterministyczny, tak. Zawsze będzie to robić dla każdej konkretnej instancji. Jednak nie ma żadnego powodu, aby wybrać od lewej do prawej, od prawej do lewej, kolejność efektów.

Jednak z the documentation for Applicative:

Jeśli f również Monad, powinna ona spełniać pure = return i (<*>) = ap (co oznacza, że ​​pure i <*> spełniać ustawowe aplikacyjnych funktora).

Definicja ap jest to, ze Control.Monad:

ap :: (Monad m) => m (a -> b) -> m a -> m b 
ap = liftM2 id 

I liftM2 jest zdefiniowana w sposób oczywisty:

liftM2 f m1 m2 = do { x1 <- m1; x2 <- m2; return (f x1 x2) } 

Oznacza to, że dla dowolnego funktora, który jest a Monad, a także Applicative, oczekuje się (według specyfikacji, ponieważ nie można tego egzekwować w kodzie), że Applicative będzie działać od lewej do prawej, tak aby blok do w liftM2 wykonał to samo, co liftA2 f x y = f <$> x <*> y.

Z tego powodu, nawet dla Applicative wystąpień bez odpowiadającego Monad, zgodnie z konwencją, efekty są zwykle uporządkowane również od lewej do prawej.

Mówiąc szerzej, ponieważ struktura obliczeń Applicative jest koniecznie niezależna od "efektów", zwykle można analizować znaczenie programu niezależnie od tego, jak sekwencje są skutkami Applicative. Na przykład, jeśli instancja dla [] została zmieniona na sekwencję od prawej do lewej, dowolny kod użyłby tego samego wyniku, z elementami listy w innej kolejności.

+0

Dziękujemy! Czy prawidłowo wywnioskuję, że jeśli kolejność efektów jest dla mnie ważna i chcę być teoretyczna, powinienem użyć Monady, ale jeśli jestem praktyczny, to czy pasuje do ciebie aplikacja (zwykle z ostrożnością)? – ron

+2

@ron: W praktyce można po prostu założyć, że instancje "Applicative" będą sekwencyjnie od lewej do prawej, chyba że głośno oznajmiają inaczej, jak w przypadku opakowania 'Backwards'. Zauważ, że instancje 'Monad' mogą być niejednoznaczne na inne sposoby - na przykład odwrócona monada' State' przywraca wartość stanu do tyłu, ale sam typ jest identyczny ze zwykłym 'State'. Dla innego przykładu, '[]' ma dwie możliwe instancje 'Applicative' nawet poza porządkiem sekwencyjnym. Nie można uniknąć polegania na tym, co mówi dokumentacja. –

+0

@ C.A.McCann "* [...] zazwyczaj można analizować znaczenie programu niezależnie od sposobu sekwencjonowania efektów aplikacyjnych. *" Dlaczego? Czy nie jest to prawdą tylko w przypadku * komutatywnych * aplikacyjnych funktorów? Ogólnie rzecz biorąc, zmiana kolejności Efekty aplikacyjne mogą radykalnie zmienić wynik. Oto jeden przykład: 'myParser = (++) <$> foo <*> bar' gdzie' foo' i 'bar' są parsec' Parser String'. Jeśli zmieniłem sekwencję na "od prawej do lewej", 'myParser' zawiedzie na wejściowym łańcuchu' "foobar" '. Czy nie zgodziłbyś się w tym przypadku, że zmiana kolejności efektów wpłynęła na znaczenie programu? – Jubobs

4

Tak, kolejność jest wstępnie zdefiniowana przez korespondencję Monad-Applicative.Jest to łatwe do patrz: (*>) syntezatora musi odpowiadać (>>) combinator w grzeczne Applicative przykład dla monady, a jego definicja jest:

a *> b = liftA2 (const id) a b 

Innymi słowy, jeśli b były wykonywane przed a, instancja Applicative byłaby niepoprawna.

Edit: Na marginesie: to nie jest wyraźnie określona w dowolnym miejscu, ale można znaleźć wiele innych podobnych odpowiedniki jak liftM2 = liftA2 itp

2

Dla IO aplikacyjnych, to z pewnością przypadek. Ale sprawdź przykład async package dla przykładu aplikacji, w której w f <$> a <*> b efekty następują równolegle.

Powiązane problemy