Преобразование монады StateT IO для использования Control.Proxy - какой сервер, а какой клиент?
Я реализую игровой движок. Большая часть моего кода в настоящее время находится в StateT Game IO ()
монада. Я использую IO, чтобы получить пользовательский ввод, и на самом деле все каналы IO через одну функцию,
getChoice :: Show a => [ a ] -> IO a
который предлагает пользователю все представленные опции, читает ответ и возвращает его. Для определенного потока пользовательских ответов (и начального состояния) игра протекает детерминистически, и я хотел бы выделить эти пользовательские ответы, чтобы помочь с тестированием.
Когда я пытаюсь преобразовать это, чтобы использовать Pipes, то, что кажется наиболее похожим, это изменить весь мой код, который в настоящее время находится в StateT Game IO ()
и заставить его работать в Proxy p, Monad m => Client p [String] String m ()
, Таким образом, я все еще могу "запрашивать" выбор у пользователя, что позволяет мне писать код движка в стиле блокировки, при условии, что выбор пользователя будет предоставлен по мере необходимости.
Однако, это кажется неправильным - конечно, пользователь должен быть клиентом, а игровой движок - сервером? Какие принципы я могу использовать, чтобы правильно провести это различие?
2 ответа
Как сказал Нусио, оба Client
а также Server
полностью симметричны друг другу. Единственное, что вводит асимметрию, это оператор композиции. (>->
) начинается с Client
конец и (>~>
) начинается с Server
конец.
Так как вы используете (>->
), это означает, что Client
Компонент имеет "инициативу" и заставляет вещи катиться. Это означает, что Server
не будет ничего делать, если Client
делает request
, Кроме того факта, что Client
начинается сначала, нет никакой разницы между Client
а также Server
,
Тип (>->
) когда вы специализируете его на Client
а также Server
отражает эту асимметрию в инициативе:
(>->) => ([String] -> Server [String] String IO r)
-> (() -> Client [String] String IO r)
-> (() -> Session IO r)
Server
(т. е. ваш пользователь) реагирует только на Client
(то есть игровой движок), поэтому сервер должен принимать аргумент типа [String]
чтобы мяч катился. Это отражается в том факте, что если игровой движок никогда не запрашивает у пользователя выбор, то пользователь "никогда не сможет работать", потому что у пользователя нет набора вариантов для выбора. От того, как вы указали проблему, движок игры контролирует, а не пользователь. Если бы вы указали это с другой стороны и чтобы пользователь управлял игровым движком, то роли были бы противоположными.
В pipes
, Server
с и Client
s почти взаимозаменяемы, как и request
а также respond
, вверх по течению и ниже по течению. Разница в том, что это Client
работа, чтобы начать Session
выполнив первый запрос.
http://hackage.haskell.org/packages/archive/pipes/2.5.0/doc/html/Control-Proxy-Tutorial.html
Я уверен, что вы можете сформулировать игрока как Client
а также Server
: это все о чувствах. Почему бы не считать его / ее сервером ввода с клавиатуры?