Konsoleninteraktivität in Netwire?

Ich teste mit demNetwire haskell Bibliothek und machte es mit einem einfachentime wire:

import Control.Wire
import Prelude hiding ((.), id)

import Control.Monad.IO.Class
import Data.Functor.Identity
import System.IO

wire :: (HasTime t s) => Wire s () m a t
wire = time

run :: (HasTime t s, MonadIO m, Show b, Show e) =>
       Session m s -> Wire s e m a b -> m ()
run session wire = do
  (dt, session') <- stepSession session
  (wt', wire') <- stepWire wire dt $ Right undefined
  case wt' of
    -- | Exit
    Left _ -> return ()
    Right x -> do
      liftIO $ do
        putChar '\r'
        putStr $ either (\ex -> show ex) show wt'
        hFlush stdout
        -- Interactivity here?
        gotInput <- hReady stdin
        if gotInput then
          return ()
          else return ()
      run session' wire'

main :: IO ()
-- main = testWire clockSession_ wire
main = run clockSession_ wire

Beachten Sie dasrun ist grundsätzlich modifiziert vontestWire, also weiß ich nicht, ob es der richtige Weg ist, ein Netzwerk von Drähten zu bilden. Ein Teil des Codes stammt vonhttp: //todayincode.tumblr.com/post/96914679355/almost-a-netwire-5-tutoria aber dieses Tutorial sagt nichts über Ereignisse aus.

Jetzt versuche ich, dem Programm ein wenig Interaktivität hinzuzufügen. Beenden Sie vorerst das Programm, wenn eine beliebige Taste gedrückt wird. Ich nehme an, ich sollte eine Ereignisumschaltung durchführen. Ich stecke jedoch hier fest, weil ich keinen Weg finde, mich zu ändernwire' oder ändere das Verhalten. Ich habe versucht, das API-Dokument und die Quelle zu lesen, aber ich verstehe nicht, wie ich ein Ereignis "auslösen" oder es zum Umschalten der Verbindung verwenden kann.

Again, da ich mit Haskell noch nicht sehr vertraut bin, habe ich hier vielleicht einige große dumme Fehler gemacht.

Update 1/2

Ich habe mein Ziel durch den folgenden Code erreicht. Der Timer stoppt bei jedem Tastendruck.Update 2 Ich konnte mich trennenpollInput in eine andereIO nur Funktion, Yay!

import Control.Wire
import Prelude hiding ((.), id)

import Control.Monad.IO.Class
import Data.Functor.Identity
import System.IO

wire :: (HasTime t s) => Wire s () m a t
wire = time

run :: (HasTime t s, MonadIO m, Show b, Show e) =>
       Session m s -> Wire s e m a b -> m ()
run session wire = do
  -- Get input here
  input <- liftIO $ pollInput

  (dt, session') <- stepSession session
  (wt', wire') <- stepWire wire dt $ input
  case wt' of
    -- | Exit
    Left _ -> liftIO (putStrLn "") >> return ()
    Right x -> do
      liftIO $ do
        putChar '\r'
        putStr $ either (\ex -> show ex) show wt'
        hFlush stdout

      run session' wire'

pollInput :: IO (Either a b)
pollInput =  do
  gotInput <- hReady stdin
  if gotInput then
    return (Left undefined)
    else return (Right undefined)


setup :: IO ()
setup = do
  hSetBuffering stdin NoBuffering
  hSetBuffering stdout NoBuffering


main :: IO ()
main = do
  setup
  run clockSession_ wire

Dies wirft jedoch einige weitere Fragen auf. Erstens ist dies eine gute Praxis?Second, was ist der Typ vonpollInput? Ich habe versucht, es manuell abzutippen, aber ohne Erfolg. Der automatische Typabzug funktioniert jedoch.

Dies ist meine Erklärung, wie dieser Code funktioniert:

Zunächst wird die Benutzereingabe von der Konsole abgefragt, und nach einer gewissen Logik wird die "Eingabe" für die Leitung generiert (schlechte Namensauswahl, aber diese generierte Eingabe ist die Leitungseingabe) und über das Netzwerk weitergeleitet. Hier übergebe ich einfach eine Hemmung Left something), und die Schleife wird beendet. Natürlich erzeugt das Programm beim Beenden eine neue Zeile, um die Konsole besser aussehen zu lassen.

(Nun, ich verstehe immer noch nicht, wieEvent funktioniert aber)

Update 3/4

achdem ich die Antwort von @Cirdec gelesen und viel an meinem Editor herumgespielt habe, erhalte ich diese Single-Thread-Version ohneIORef, wird auch beim Drücken von 'x' beendetUpdate 4: (gibt aber nichts aus):

import Control.Wire
import Prelude hiding ((.),id)
import Control.Wire.Unsafe.Event
import System.IO
import Control.Monad.IO.Class

data InputEvent = KeyPressed Char 
                | NoKeyPressed
                deriving (Ord, Eq, Read, Show)
type OutputEvent = IO ()

--- Wires
example :: (HasTime t s, Monad m, Show t) =>
           Wire s () m (Event [InputEvent]) (Event [OutputEvent])
example = switch $
          (fmap ((:[]) . print) <
import Control.Wire
import Prelude hiding ((.),id)
import Control.Wire.Unsafe.Event
import System.IO
import Control.Monad.IO.Class

data InputEvent = KeyPressed Char 
                | NoKeyPressed
                deriving (Ord, Eq, Read, Show)
type OutputEvent = IO ()

--- Wires
example :: (HasTime t s, Monad m, Show t) =>
           Wire s () m (Event [InputEvent]) (Event [OutputEvent])
example = switch $
          (fmap ((:[]) . print) <$> periodic 1 . time
           &&&
           fmap (const mkEmpty) <$> filterE (any (== KeyPressed 'x'))
           )

readKeyboard :: IO (Either e (InputEvent))
readKeyboard = do
  hSetBuffering stdin NoBuffering
  gotInput <- hReady stdin
  if gotInput then do
    c <- getChar
    return $ Right $ KeyPressed c
    else return $ Right $ NoKeyPressed

output :: [OutputEvent] -> IO ()
output (x:xs) = id x >> output xs
output _ = return ()

run :: (HasTime t s, MonadIO m) =>
       Session m s -> Wire s e m (Event [InputEvent]) (Event [OutputEvent]) -> m e
run = go
  where
    go session wire = do
      -- | inputEvent :: Event InputEvent
      inputEvent <- liftIO $ readKeyboard
      (dt, session') <- stepSession session
      (wt', wire') <- stepWire wire dt (Event <$> (fmap (:[]) inputEvent))
      -- (wt', wire') <- stepWire wire dt (Right undefined)
      case wt' of
        Left a -> return a
        Right bEvent -> do
          case bEvent of
            Event b -> liftIO $ output b
            _ -> return ()
          go session' wire'

main = do
  run clockSession_ example
gt; periodic 1 . time &&& fmap (const mkEmpty) <
import Control.Wire
import Prelude hiding ((.),id)
import Control.Wire.Unsafe.Event
import System.IO
import Control.Monad.IO.Class

data InputEvent = KeyPressed Char 
                | NoKeyPressed
                deriving (Ord, Eq, Read, Show)
type OutputEvent = IO ()

--- Wires
example :: (HasTime t s, Monad m, Show t) =>
           Wire s () m (Event [InputEvent]) (Event [OutputEvent])
example = switch $
          (fmap ((:[]) . print) <$> periodic 1 . time
           &&&
           fmap (const mkEmpty) <$> filterE (any (== KeyPressed 'x'))
           )

readKeyboard :: IO (Either e (InputEvent))
readKeyboard = do
  hSetBuffering stdin NoBuffering
  gotInput <- hReady stdin
  if gotInput then do
    c <- getChar
    return $ Right $ KeyPressed c
    else return $ Right $ NoKeyPressed

output :: [OutputEvent] -> IO ()
output (x:xs) = id x >> output xs
output _ = return ()

run :: (HasTime t s, MonadIO m) =>
       Session m s -> Wire s e m (Event [InputEvent]) (Event [OutputEvent]) -> m e
run = go
  where
    go session wire = do
      -- | inputEvent :: Event InputEvent
      inputEvent <- liftIO $ readKeyboard
      (dt, session') <- stepSession session
      (wt', wire') <- stepWire wire dt (Event <$> (fmap (:[]) inputEvent))
      -- (wt', wire') <- stepWire wire dt (Right undefined)
      case wt' of
        Left a -> return a
        Right bEvent -> do
          case bEvent of
            Event b -> liftIO $ output b
            _ -> return ()
          go session' wire'

main = do
  run clockSession_ example
gt; filterE (any (== KeyPressed 'x')) ) readKeyboard :: IO (Either e (InputEvent)) readKeyboard = do hSetBuffering stdin NoBuffering gotInput <- hReady stdin if gotInput then do c <- getChar return $ Right $ KeyPressed c else return $ Right $ NoKeyPressed output :: [OutputEvent] -> IO () output (x:xs) = id x >> output xs output _ = return () run :: (HasTime t s, MonadIO m) => Session m s -> Wire s e m (Event [InputEvent]) (Event [OutputEvent]) -> m e run = go where go session wire = do -- | inputEvent :: Event InputEvent inputEvent <- liftIO $ readKeyboard (dt, session') <- stepSession session (wt', wire') <- stepWire wire dt (Event <
import Control.Wire
import Prelude hiding ((.),id)
import Control.Wire.Unsafe.Event
import System.IO
import Control.Monad.IO.Class

data InputEvent = KeyPressed Char 
                | NoKeyPressed
                deriving (Ord, Eq, Read, Show)
type OutputEvent = IO ()

--- Wires
example :: (HasTime t s, Monad m, Show t) =>
           Wire s () m (Event [InputEvent]) (Event [OutputEvent])
example = switch $
          (fmap ((:[]) . print) <$> periodic 1 . time
           &&&
           fmap (const mkEmpty) <$> filterE (any (== KeyPressed 'x'))
           )

readKeyboard :: IO (Either e (InputEvent))
readKeyboard = do
  hSetBuffering stdin NoBuffering
  gotInput <- hReady stdin
  if gotInput then do
    c <- getChar
    return $ Right $ KeyPressed c
    else return $ Right $ NoKeyPressed

output :: [OutputEvent] -> IO ()
output (x:xs) = id x >> output xs
output _ = return ()

run :: (HasTime t s, MonadIO m) =>
       Session m s -> Wire s e m (Event [InputEvent]) (Event [OutputEvent]) -> m e
run = go
  where
    go session wire = do
      -- | inputEvent :: Event InputEvent
      inputEvent <- liftIO $ readKeyboard
      (dt, session') <- stepSession session
      (wt', wire') <- stepWire wire dt (Event <$> (fmap (:[]) inputEvent))
      -- (wt', wire') <- stepWire wire dt (Right undefined)
      case wt' of
        Left a -> return a
        Right bEvent -> do
          case bEvent of
            Event b -> liftIO $ output b
            _ -> return ()
          go session' wire'

main = do
  run clockSession_ example
gt; (fmap (:[]) inputEvent)) -- (wt', wire') <- stepWire wire dt (Right undefined) case wt' of Left a -> return a Right bEvent -> do case bEvent of Event b -> liftIO $ output b _ -> return () go session' wire' main = do run clockSession_ example

Ich denke, das ist viel besser als mein Original, aber ich bin immer noch nicht ganz überzeugt, ob es eine gute Übung ist oder nicht.

Antworten auf die Frage(4)

Ihre Antwort auf die Frage