Interatividade do console no Netwire?

Estou testando com oNetwire biblioteca haskell e fez funcionar com um simplestime fio:

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

Note orun é basicamente modificado detestWire, então não sei se é a maneira correta de formar uma rede de fios. Parte do código de origem dehttp://todayincode.tumblr.com/post/96914679355/almost-a-netwire-5-tutorial mas esse tutorial não diz sobre eventos.

Agora estou tentando adicionar um pouco de interatividade ao programa. Por enquanto, feche o programa quando qualquer tecla for pressionada. Suponho que devo fazer alguma troca de eventos. No entanto, estou preso aqui porque não consigo encontrar uma maneira de mudarwire' ou mude o comportamento. Tentei ler o documento da API e a fonte, mas não vejo como realmente "acionar" um evento ou usá-lo para mudar o fio.

Novamente, como ainda não estou muito familiarizado com Haskell, posso ter cometido alguns grandes erros estúpidos aqui.

Atualização 1/2

Meu objetivo foi trabalhar com o seguinte código. O temporizador para com qualquer tecla pressionada.Atualização 2 Eu consegui separarpollInput em outroIO única função, 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

No entanto, isso levanta algumas questões adicionais. Primeiro, essa é uma boa prática?Segundo, qual é o tipo depollInput? Tentei digitar manualmente, mas sem sucesso. A dedução automática de tipo funciona, no entanto.

Esta é minha explicação de como esse código funciona:

Primeiro, a entrada do usuário do console é pesquisada e, após alguma lógica, a "entrada" para ligação é gerada (má escolha de nome, mas essa entrada gerada é a entrada de conexão) e transmitida pela rede. Aqui, eu simplesmente passo uma inibição (Left something) e fará com que o loop saia. Obviamente, ao sair, o programa produz uma nova linha para tornar o console mais agradável.

(Bem, eu ainda não entendo comoEvent funciona, no entanto)

Atualização 3/4

Depois de ler a resposta do @Cirdec e mexer bastante no meu editor, recebo esta versão com thread único semIORef, também saindo ao pressionar 'x'Atualização 4: (mas não produz nada):

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

Acho que isso é muito melhor que o meu original, mas ainda não estou completamente convencido de que seja uma boa prática ou não.

questionAnswers(2)

yourAnswerToTheQuestion