Получение информации о программах Netwire
Я начинаю с Netwire версии 5.
У меня нет проблем с записью всех проводов, которые я хочу преобразовать в мои входы.
Теперь пришло время написать оболочку ввода-вывода, чтобы связать ее с реальными данными, и я немного запутался.
Я должен создать пользовательский тип сеанса для s
параметр Wire s e m a b
и вставлять там значения моего датчика?
Если так, у меня есть следующие вопросы:
- Что случилось с
Monoid s
контекстclass (Monoid s, Real t) => HasTime t s | s -> t
? Для чего его используют? - Я думал о том, чтобы
Map String Double
с моими показаниями датчика, но как мой моноид должен хрустить словари? Должен ли он быть смещенным влево? Право предвзятым? Ни один из вышеперечисленных?
Если нет, что я должен делать? Я хочу в конечном итоге с проводами в форме Wire s InhibitionReason Identity () Double
для некоторых s
, представляющий мой вклад.
Это мое понимание, что я не хочу или не нужно использовать монадический m
параметр Wire
для этого, позволяя самим проводам быть чистыми и ограничивая ввод-вывод кодом, который проходит по проводам верхнего уровня. Это неверно?
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
Я только что решил это способом Arrow, так что это может быть более сложным. Вы можете прочитать мои сообщения, если хотите. Клейсли Стрелка в 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)