Haskell中为骰子分配场景实现State Monad及函子等实例
自定义State Monad实现与骰子属性状态管理
1. 核心State类型定义
按照Graham Hutton的思路,先定义State monad的基础类型:
newtype State s a = State { runState :: s -> (a, s) }
s代表状态的类型(这里我们用[Int]表示剩余骰子池)a代表计算返回的结果类型runState函数用于执行State计算,传入初始状态后返回结果和更新后的状态
2. Functor实例实现
instance Functor (State s) where fmap f (State sa) = State $ \s -> let (a, s') = sa s in (f a, s')
将函数f映射到State计算的结果上,状态传递保持不变。
3. Applicative实例实现
instance Applicative (State s) where pure a = State $ \s -> (a, s) (State sf) <*> (State sa) = State $ \s -> let (f, s') = sf s (a, s'') = sa s' in (f a, s'')
pure创建一个不修改状态的计算,直接返回给定值<*>先执行生成函数的State计算,再用新状态执行生成值的计算,最后将函数应用到值上
4. Monad实例实现
instance Monad (State s) where return = pure (State sa) >>= f = State $ \s -> let (a, s') = sa s (State sb) = f a in sb s'
return同pure,用于包装值为State计算>>=(绑定操作)先执行第一个State计算得到结果和新状态,再用该结果生成第二个State计算,最后在新状态上执行第二个计算
5. 实用状态操作辅助函数
定义两个常用的状态操作函数简化开发:
-- 获取当前状态 get :: State s s get = State $ \s -> (s, s) -- 更新状态 put :: s -> State s () put s = State $ \_ -> ((), s)
6. 骰子属性分配逻辑实现
我们用纯函数模拟属性分配,忽略IO交互部分:
-- 定义角色属性类型 data Attribute = Strength | Dexterity | Constitution deriving (Show) type AttributeValue = Int type DicePool = [Int] -- 剩余骰子池类型 -- 分配n个骰子到指定属性,返回属性及总和,自动更新骰子池状态 allocateAttribute :: Attribute -> Int -> State DicePool (Attribute, AttributeValue) allocateAttribute attr n = do currentDice <- get let (usedDice, remainingDice) = splitAt n currentDice total = sum usedDice put remainingDice return (attr, total)
7. 使用示例
模拟初始骰子池,执行属性分配序列:
-- 模拟掷出的初始骰子结果 initialDice :: DicePool initialDice = [4, 6, 3, 5, 2, 4] -- 定义完整的属性分配流程 assignAttributes :: State DicePool [(Attribute, AttributeValue)] assignAttributes = do strength <- allocateAttribute Strength 3 dexterity <- allocateAttribute Dexterity 2 constitution <- allocateAttribute Constitution 1 return [strength, dexterity, constitution] -- 运行State计算并查看结果 main :: IO () main = print $ runState assignAttributes initialDice
执行后会输出:
([(Strength,13),(Dexterity,7),(Constitution,4)],[])
可以看到State monad自动管理了骰子池的状态,无需手动传递剩余骰子。
内容的提问来源于stack exchange,提问作者Yago
相关产品推荐
相关产品推荐

