我对Haskell很陌生并且练习,我决定制作一款d& d风格的游戏,其中战斗基于掷骰子,而拥有更多数字的人则获胜。但是,我对如何更改记录的值并更改记录的全局值感到困惑。
这是我的记录代码:
data PlayerStats = PlayerStats { health :: Health
,mana :: Mana
,inventory :: [Items] }deriving (Show,Eq)
defaultStats = PlayerStats {health = 100, mana = 50, inventory = []}
如果玩家输掉骰子,这就是我的功能:
takeDamage:: State PlayerStats ()
takeDamage = do
let h = defaultStats health
h <- get
put $ (h - 10)
我在互联网上寻找像我这样的问题的解决方案,但没有找到任何东西,所以我认为这对我所处的其他人有用。
答案 0 :(得分:3)
首先,defaultStats :: PlayerStats
,这是一个记录,而不是一个函数,所以:
defaultStats health
没有意义。另一方面,health :: PlayerStats -> Health
是一个函数,所以
health defaultStats
更有意义,但基本上是常数100
,因为那是health
的{{1}}。但是,在这种情况下,它没有意义,因为你立即引入一个新的defaultStats
,绑定到h
,(假设get
是State
)得到来自Control.Monad.Trans.State
PlayerStats
的当前State
。请注意,Monad
将是整个h
,而不仅仅是PlayerStats
组件。
记录更新确实会从现有记录中创建一条新记录,其中一个或多个字段将替换为新值。在这种情况下,您希望将health
字段替换为当前值减去health
:
10
在这里,我们从takeDamage = do
ps <- get
put $ ps { health = health ps - 10 }
PlayerStats
获取当前State
为Monad
,然后ps
为新put
基于当前的一个,但PlayerStats
字段设置为当前health
减去health
。在记录更新语法中,10
左侧的health
表示字段名称,右侧的=
表示获取health
的访问者函数来自现有记录的字段。
health
后面跟着get
很常见,有一个put
函数,它接受一个转换状态的函数,并用modify
和{{包装它1}}:
get
记录更新语法是一个巨大的Haskell疣。您可能需要查看lenses,这样可以非常轻松地更新put
takeDamage = modify $ \ps -> ps { health = health ps - 10 }
中的字段(尽管当您陷入困境时收到的错误消息会让您的大脑融化)。
修改强>
如果你想看看你的玩家是否失去了所有健康状况,你可以让State
函数返回一个Monad
来表明该玩家是否幸存下来:
takeDamage