Ввод данных в программы Netwire

Я начинаю работу с Netwire версии 5.

У меня нет проблем с написанием всех проводов, которые я хочу преобразовать в свои входы в свои выходы.

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

Должен ли я создать собственный тип сеанса для параметра s параметра Wire s e m a b и внедрить туда значения своих датчиков?

Если да, то у меня такие вопросы:

  1. Что случилось с Monoid s контекстом class (Monoid s, Real t) => HasTime t s | s -> t? Для чего его используют?
  2. Я думал прикрутить Map String Double к своим показаниям сенсора, но как мой моноид должен хрустить словарями? Должен ли он быть левым? Правостороннее? Ни один из вышеперечисленных?

Если нет, то что мне делать? Я хочу получить провода вида Wire s InhibitionReason Identity () Double для некоторого s, представляющего мой ввод.

Насколько я понимаю, я не хочу и не должен использовать монадический параметр m для Wire для этой цели, позволяя самим проводам быть чистыми и ограничивая ввод-вывод кодом, который проходит через провода верхнего уровня. Это неправильно?


person Doug McClean    schedule 04.04.2014    source источник
comment
Есть экземпляр моноида для Map, который остается предвзятым. И я на самом деле думаю, что сделать здесь монадический контекст монадой чтения и наполнить ее сенсорной информацией было бы разумно. Это на самом деле не влияет на место, где вы прокладываете провода, потому что вы можете просто runReader (или runReaderT, если хотите добавить еще больше вещей).   -  person Cubic    schedule 05.04.2014
comment
Учебники/примеры предлагают использовать действия ввода-вывода во внутренних проводах для получения данных датчика. например используйте mkGen_ с getKey в нем. Мне было бы интересно обобщить вопрос: каковы преимущества и недостатки разрешения операций ввода-вывода внутри проводов по сравнению с подачей всех данных ввода-вывода в качестве входных данных для самого внешнего провода?   -  person crosser    schedule 17.11.2014


Ответы (2)


Самый простой способ поместить данные в Wire s e m a b — через ввод a. С помощью WPure или WGen можно получить данные из дельты состояния s или базовой Monad m, но это уводит нас дальше от основных абстракций. Основные абстракции — это Arrow и Category, которые знают только о a b, а не о s e m.

Вот пример очень простой программы, предоставляющей ввод как ввод a. double — самый внешний провод программы. repl — это небольшой цикл чтения-оценки-печати, который вызывает stepWire для запуска проводника.

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

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

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

main = repl timeString 

Который имеет желаемый результат:

a
1
b
2
c
3
person Cirdec    schedule 03.09.2014

Я только что решил это стрелкой, так что это может быть более компонуемым. Вы можете прочитать мои сообщения, если хотите. Стрелка Клейсли в Netwire 5? и Интерактивность консоли в Netwire?. Второй пост имеет полную интерактивную программу

Во-первых, вам нужно это, чтобы поднять функции Клейсли (то есть что-нибудь 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

Затем, если вы хотите получить символы из терминала, вы можете поднять hGetChar, выполнив следующие действия:

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

Я не тестировал эту функцию runWire (я просто вырезал код из своих предыдущих постов), но она должна работать с вашими проводами:

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'

Вы можете скомпоновать входной провод где угодно, как и любые другие провода или стрелки. В своем примере я сделал так (не просто копировать, другие части программы разные):

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

Или, однострочный:

mainWire = inputWire >>> (quitWire &&& outputWire) >>> arr (\(q,_) -> q)
person Carl Dong    schedule 29.09.2015