背景:我创建了一个有状态monad的游戏,用于读取和写入游戏全局状态的变化。
我想将我的游戏划分为组件,例如" Characters",为这些组件提供特定于域的方式与全局状态进行交互。理想情况下,这可能会定义我可以使用的MonadState Character m => m a
形式的特定操作,但每个m a
都会对父项(全局状态)进行更改。
我已经四处寻找状态monad之间的转换,或者提供从一个状态monad到另一个状态monad的接口,但是具体的语言超出了我的知识范围。我也在使用镜头,我想知道我是否可以用它们做点什么。
修改:
我希望能够做类似的事情
moveCharacter :: MonadState Character m => Int -> Int -> m ()
并在内部执行move :: MonadState World m => Int -> Int -> m ()
。基本上,从世界中抽象出世界细节。
谢谢!
答案 0 :(得分:3)
听起来你正在寻找Zoom
,这可以让你将镜头视角上的有状态动作转换为镜头光源上的状态动作。
答案 1 :(得分:0)
您实际上需要2个转换函数:一个用于从世界中提取角色,另一个用修改后的角色修改世界。你可以把它们放在一起:
extractCharacter :: World -> Character
extractCharacter = error "Tried to call placeholder function"
replaceCharacter :: World -> Character -> World
replaceCharacter = error "Tried to call placeholder function"
runCharacterSubroutine :: (Functor m) =>
StateT Character m a -> StateT World m a
runCharacterSubroutine act = StateT $ \w ->
fmap (\(a,c') -> (a,replaceCharacter w c')) $
runStateT act (extractCharacter w)
在你的游戏中,你可能想要一些更复杂的东西,但这只是在extractCharacter
和replaceCharacter
添加额外参数的问题
请注意,只有当StateT
位于monad变换器堆栈的顶部时,我给出的函数才有效。如果不是:您必须使用mmorph
包