Преобразование монады 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с и Clients почти взаимозаменяемы, как и request а также respond, вверх по течению и ниже по течению. Разница в том, что это Clientработа, чтобы начать Session выполнив первый запрос.

http://hackage.haskell.org/packages/archive/pipes/2.5.0/doc/html/Control-Proxy-Tutorial.html

Я уверен, что вы можете сформулировать игрока как Client а также Server: это все о чувствах. Почему бы не считать его / ее сервером ввода с клавиатуры?

Другие вопросы по тегам