2014-04-04 15 views
11

Ich fange mit Netwire Version 5 an.Eingabe in Netwire-Programme

Ich habe kein Problem, alle Drähte zu schreiben, die ich meine Eingänge in meine Ausgaben umwandeln möchte.

Jetzt ist es an der Zeit, den IO-Wrapper zu schreiben, um meine realen Eingaben zu verknüpfen, und ich bin ein wenig verwirrt.

Soll ich einen benutzerdefinierten Sitzungstyp für den s Parameter von Wire s e m a b erstellen und meine Sensorwerte dort einbetten?

Wenn ja, habe ich diese Fragen:

  1. Was mit dem Monoid s Kontext class (Monoid s, Real t) => HasTime t s | s -> t ist oben? Was wird es verwendet?
  2. Ich dachte an einen Map String Double mit meinen Sensorablesungen, aber wie sollte mein Monoid die Wörterbücher knacken? Sollte es linksbündig sein? Rechts-voreingenommen? Nichts des oben Genannten?

Wenn nicht, was soll ich tun? Ich möchte enden mit Drähten der Form Wire s InhibitionReason Identity() Double für einige s, die meine Eingabe darstellen.

Es ist mein Verständnis, dass ich nicht den monadischen m Parameter von Wire für diesen Zweck verwenden möchte und muss, die Drähte selbst rein sein und die IO auf den Code beschränken, der durch die oberste Ebene geht (s). Ist das falsch?

+0

Es gibt ein Monoid Beispiel für Map, die übrig geblieben sind voreingenommen. Und ich würde tatsächlich denken, den monadischen Kontext hier zu einer Leser-Monade zu machen und die Sensorinformationen dort hinein zu packen, wäre hier vernünftig. Dies beeinflusst nicht wirklich den Ort, an dem du deine Drähte steckst, weil du einfach "runReader" (oder "runReaderT", wenn du noch mehr Sachen stopfen willst). – Cubic

+0

Tutorials/Beispiele da draußen schlagen vor, IO-Aktionen in inneren Drähten zu verwenden, um Sensordaten zu erhalten. z.B. benutze 'mkGen_' mit' getKey' darin. Ich wäre daran interessiert, die Frage zu verallgemeinern: "Was sind die Vor- und Nachteile von IO-Aktionen innerhalb von Drähten, verglichen mit der Einspeisung aller IO-Daten als Eingang für die äußerste Leitung?" – crosser

Antwort

2

Die einfachste Möglichkeit, Daten in eine Wire s e m a b zu setzen, ist über den Eingang a. Es ist möglich, durch die Verwendung von WPure oder WGen Daten aus dem Status-Delta s oder dem zugrunde liegenden Monadm zu bekommen, aber diese entfernen uns weiter weg von den Haupt-Abstraktionen. Die Hauptabstraktionen sind Arrow und Category, die nur ungefähr a b kennen, und nicht über s e m.

Hier ist ein Beispiel für ein sehr einfaches Programm, Eingabe als die Eingabe a. double ist der äußerste Draht des Programms. repl ist eine kleine Read-Eval-Print-Schleife, die stepWire aufruft, um den Draht zu führen.

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 

Beachten Sie, dass wir in der Zeitdifferenz zu stepWire passieren, nicht die gesamte verstrichene Zeit. Wir können überprüfen, ob dies richtig ist, indem Sie einen anderen Top-Level-Draht ausführen.

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

main = repl timeString 

, die den gewünschten Ausgang hat:

a 
1 
b 
2 
c 
3 
1

Ich löste dies nur in einem Pfeil Art und Weise, so könnte dies mehr composible sein. Sie können meine Beiträge lesen, wenn Sie möchten. Kleisli Arrow in Netwire 5? und Console interactivity in Netwire?.Der zweite Beitrag hat ein umfassendes interaktives Programm

Zuerst Sie diese Kleisli Funktionen heben müssen (Das heißt, alles 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 

Dann vorausgesetzt, Sie Zeichen von Terminal erhalten möchten, können Sie heben hGetChar durch dies zu tun:

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

ich diese runWire Funktion nicht getestet (I off nur gestrippt Code aus meinen früheren Beiträgen), aber es sollte Ihre Drähte läuft:

Sie können die Eingangsleitung wie auch andere Drähte oder Pfeile an beliebiger Stelle zusammenstellen. In meinem Beispiel habe ich diese (nicht einfach kopieren, andere Teile des Programms verschieden sind):

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

Oder Einzeiler:

mainWire = inputWire >>> (quitWire &&& outputWire) >>> arr (\(q,_) -> q)