Haskell - 我将如何运行状态单子(monad)列表?

标签 haskell functional-programming state-monad

我对 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/

相关文章:

haskell - 如何在 Haskell 中获取标记联合数据类型的值?

functional-programming - SML/NJ 中的环路

haskell - 了解 "Programming In Haskell"第 12 章中的应用问题 (#7)

scala - 试图理解 scalaz 状态 monad

haskell - 无法理解 State Monad 如何在此代码中获取它的状态

haskell - 我如何将 runhaskell 与 cabal-dev 一起使用?

haskell - 由于使用 ‘a0’ 而产生的模糊类型变量 ‘Ex.catch’

haskell - 无法定义无限流

javascript - 每个星期五直到某个日期,但以实用的方式?

haskell - 在 Haskell 中组合 monad