我正在实施游戏引擎。我的大多数代码目前都驻留在StateT Game IO ()
monad中。我使用IO来获取用户输入,实际上所有IO通道都通过一个函数
getChoice :: Show a => [ a ] -> IO a
提示用户显示所有选项,读入响应并返回。对于特定的用户响应流(和初始状态),游戏确定性地进行,并且我想将这些用户响应分解出来以帮助进行测试。
当我尝试将其转换为使用管道时,最相似的是更改当前位于StateT Game IO ()
的所有代码,并使其在Proxy p, Monad m => Client p [String] String m ()
中运行。这样我仍然可以“请求”用户的选择,这允许我以阻塞样式编写引擎代码,假设将根据需要提供用户选择。
然而,这似乎是错误的 - 用户应该是客户端,游戏引擎是服务器吗?我可以用什么原则来正确区分这个区别?
答案 0 :(得分:1)
在pipes
中,Server
和Client
几乎可以互换,上游和下游也是request
和respond
。一个区别是,Client
通过发出第一个请求来Session
开始工作。
http://hackage.haskell.org/packages/archive/pipes/2.5.0/doc/html/Control-Proxy-Tutorial.html
我很确定你可以将游戏玩家制定为Client
和Server
:这完全取决于感官。为什么不把他/她当作键盘输入服务器?
答案 1 :(得分:1)
像nushio所说,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]
类型的参数才能得到球的原因滚动。这反映在以下事实中:如果游戏引擎从不提示用户进行选择,则用户“永远不能运行”,因为用户没有选择的选择集。从您指定问题的方式来看,游戏引擎处于控制之中,而不是用户。如果您以相反的方式指定它并让用户驱动游戏引擎,则角色将被颠倒。