Интерактивность консоли в Netwire?

Я тестирую сNetwire библиотека haskell и заставила его работать с простымtime провод:

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

Обратите вниманиеrun в основном модифицируется изtestWire, поэтому я не знаю, является ли это правильным способом формирования сети проводов. Часть кода происходит отhttp://todayincode.tumblr.com/post/96914679355/almost-a-netwire-5-tutorial но этот учебник не говорит о событиях.

Сейчас я пытаюсь добавить немного интерактивности в программу. На данный момент выйдите из программы, когда нажата любая клавиша. Я полагаю, я должен сделать некоторые переключения событий. Тем не менее, я застрял здесь, потому что я не могу найти способ изменитьwire' или поменяй поведение. Я пытался прочитать документ API и источник, но я не вижу, как на самом деле «запустить» событие или использовать его для переключения проводов.

Опять же, поскольку я еще не очень хорошо знаком с Haskell, возможно, я допустил здесь несколько глупых ошибок.

Обновление 1/2

Я получил свою цель, работая по следующему коду. Таймер останавливается при любом нажатии клавиши.Обновление 2 Мне удалось отделитьpollInput в другойIO Единственная функция, ууу!

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

Однако это вызывает некоторые дополнительные вопросы. Во-первых, это хорошая практика?Во-вторых, какой типpollInput? Я пытался набрать его вручную, но безуспешно. Автоматический вывод типа работает, хотя.

Это мое объяснение того, как работает этот код:

Во-первых, пользовательский ввод с консоли опрашивается, и после некоторой логики генерируется «вход» для проводного соединения (плохой выбор имени, но этот входной сигнал является входным проводным) и передается по сети. Здесь я просто передаю запрет (Left something), и вызовет выход из цикла. Конечно, при выходе программа выводит новую строку, чтобы консоль выглядела лучше.

(Ну, я до сих пор не понимаю, какEvent работает, правда)

Обновление 3/4

Прочитав ответ @Cirdec и много поиграв в мой редактор, я получаю эту однопоточную версию безIORefтакже выходя из нажатия на «х»Обновление 4: (но это ничего не выводит):

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

Я думаю, что это намного лучше, чем мой оригинал, но я все еще не до конца уверен, является ли это хорошей практикой или нет.

Ответы на вопрос(2)

Ваш ответ на вопрос