2014-04-04 12 views
11

jestem Pierwsze kroki z Netwire wersji 5.Pierwsze wejście do programów Netwire

nie mam problemu piśmie wszystkie przewody, które chcę przekształcić moje wejść do mojego wyjścia.

Teraz nadszedł czas, aby napisać opakowanie IO, aby powiązać moje wejścia do świata rzeczywistego i jestem nieco zdezorientowany.

Czy mam utworzyć niestandardowy typ sesji dla parametru s z Wire s e m a b i osadzić tam moje wartości czujników?

Jeśli tak, to mam następujące pytania:

  1. Co się dzieje z kontekstem class (Monoid s, Real t) => HasTime t s | s -> tMonoid s? Do czego jest to używane?
  2. Myślałem o sczepianiu na Map String Double z moimi odczytami z czujników, ale jak mam monofoniczny skrupułować słowniki? Czy powinien być lewostronny? Zgadza się? Żadne z powyższych?

Jeśli nie, co mam zrobić? Chcę kończyć się przewodami w postaci Wire s InhibitionReason Identity() Double dla niektórych s, reprezentujących moje wejście.

Rozumiem, że nie chcę ani nie potrzebuję używać monadycznego parametru m z Wire w tym celu, pozwalając, aby same przewody były czyste i ograniczając IO do kodu przechodzącego przez przewód najwyższego poziomu (s). Czy to jest nieprawidłowe?

+0

Jest monoid instancja na mapie, co pozostało stronniczy. I pomyślałbym, że monadyczny kontekst tutaj monada czytająca i wypychanie informacji o czujniku jest rozsądne. To naprawdę nie ma wpływu na miejsce, w którym podnosisz przewody, ponieważ możesz po prostu "runReader" (lub "runReaderT", jeśli chcesz spakować jeszcze więcej rzeczy). – Cubic

+0

Samouczki/przykłady sugerują użycie operacji IO w przewodach wewnętrznych w celu uzyskania danych z czujnika. na przykład użyj 'mkGen_' z' getKey' w nim. Byłbym zainteresowany uogólnieniem tego pytania: "Jakie są zalety i wady dopuszczenia operacji IO wewnątrz przewodów, w porównaniu do podawania wszystkich danych IO jako danych wejściowych do zewnętrznego przewodu?" – crosser

Odpowiedz

2

Najprostszym sposobem umieszczenia danych w Wire s e m a b jest wejście a. Możliwe jest, dzięki zastosowaniu WPure lub WGen, uzyskanie danych z delty stanu s lub bazowej Monadm, ale te prowadzą nas dalej od głównych abstrakcji. Główne abstrakcje to Arrow i Category, które znają tylko około a b, a nie o s e m.

Oto przykład bardzo prostego programu, dostarczającego dane wejściowe jako dane wejściowe a. double jest zewnętrznym przewodem programu. repl to mała pętla do odczytu i zapisu, która wywołuje stepWire, aby uruchomić przewód.

import FRP.Netwire 
import Control.Wire.Core 

import Prelude hiding (id, (.)) 

double :: Arrow a => a [x] [x] 
double = arr (\xs -> xs ++ xs) 

repl :: Wire (Timed Int()) e IO String String -> IO() 
repl w = do 
    a <- getLine 
    (eb, w') <- stepWire w (Timed 1()) (Right a) 
    putStrLn . either (const "Inhibited") id $ eb 
    repl w' 

main = repl double 

Zauważ, że mijamy się różnicę czasu do stepWire, a nie całkowity czas. Możemy sprawdzić, czy to jest właściwa rzecz, uruchamiając inny przewód wysokiego poziomu.

timeString :: (HasTime t s, Show t, Monad m) => Wire s e m a String 
timeString = arr show . time 

main = repl timeString 

który ma pożądany wynik:

a 
1 
b 
2 
c 
3 
1

właśnie rozwiązał ten w strzałką sposób, więc może to być więcej composible. Możesz przeczytać moje posty, jeśli chcesz. Kleisli Arrow in Netwire 5? i Console interactivity in Netwire?.Drugi post ma pełny interaktywny program

pierwsze, trzeba to podnieść funkcje Kleisli (czyli coś a -> m b):

mkKleisli :: (Monad m, Monoid e) => (a -> m b) -> Wire s e m a b 
mkKleisli f = mkGen_ $ \a -> liftM Right $ f a 

Następnie, zakładając chcesz uzyskać znaki z terminala można podnosić hGetChar w ten sposób:

inputWire :: Wire s() IO() Char 
inputWire = mkKleisli $ \_ -> hGetChar stdin 

nie testowałem tego runWire funkcji (po prostu pozbawiony kod off z moich poprzednich postów), ale należy go uruchomić swoje przewody:

runWire :: (Monad m) => Session m s -> Wire s e m()() -> m() 
runWire s w = do 
    (ds, s') <- stepSession s 
    -- | You don't really care about the() returned 
    (_, w') <- stepWire w ds (Right()) 
    runWire s' w' 

Możesz komponować przewód wejściowy, gdzie chcesz, jak inne przewody lub strzałki. W moim przykładzie, zrobiłem to (nie tylko kopiowanie, pozostałe części programu są różne):

mainWire = proc _ -> do 
    c <- inputWire -<() 
    q <- quitWire -< c 
    outputWire -< c 
    returnA -< q 

Albo jedno-liner:

mainWire = inputWire >>> (quitWire &&& outputWire) >>> arr (\(q,_) -> q) 
Powiązane problemy