我对 Haskell 有点陌生,并且在 State monad 方面遇到了一些麻烦。
我创建了以下类型。
Stat a
为其创建了一个幺半群、仿函数、应用程序和 monad 实例。
我的程序中的“主要”类型是生物,它有很多参数:
data Creature = Creature {
strength :: Stat Integer,
dexterity :: Stat Integer,
...
}
data Stat a = Stat {
modifiers :: [StatModifier],
stat :: a
}
data StatModifier = StatModifier {
modifierType :: ModifierType,
value :: Integer
}
data ModifierType =
Enhancement
| Morale
| ...
生物身上可能会发生很多事情。我选择用状态单子(monad)来表示这些东西:
anyPossibleChange :: State Creature Creature
这可能是对生物造成的伤害,生物力量的增强,基本上任何东西。任何事情的可能性让我认为 State monad 是一个不错的选择。我将接受原始状态的生物,执行一些修改,然后以元组形式返回原始状态和新状态。
原始状态可能是:
Creature {
strength = Stat [] 10,
dexterity = Stat [] 10
}
最终状态可能是:
Creature {
strength = Stat [StatModifier Enhancement 2] 10,
dexterity = Stat [StatModifier Enhancement 4, StatModifier Morale 2] 10
}
我想建立一个生物需要经历的所有变化的列表,然后让生物经历所有这些变化。
这是我想要的签名,但我在实现时遇到了困难。我愿意接受不同的情况。
applyChanges :: Creature -> [State Creature Creature] -> Creature
我觉得我应该能够通过折叠来做到这一点,可能是 FoldM
但我的大脑已经被这些类型所困扰。
好的实现应该是什么样的?
最佳答案
State Creature Creature
对于这种计算来说是错误的类型。正如您所看到的,您可以逃脱它,但它不必要地使事情变得复杂,因为您实际上根本不关心状态变量!您只需使用它来存储函数的原始输入...然后将其丢弃在 applyChanges
中。
一种更容易使用的类型是Creature -> Creature
,然后如果您有一个要应用的此类函数的列表,您只需将它们全部组合起来即可,您可以这样做有折叠:
applyChanges :: [Creature -> Creature] -> Creature -> Creature
applyChanges = foldr (.) id
关于Haskell - 我将如何运行状态单子(monad)列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44193347/