《炉石传说》建模代码中attackMM函数的类型不匹配问题
排查Haskell《炉石传说》建模代码中attackMM的类型错误
看起来你在attackMM函数里把Monad的使用逻辑和返回类型要求搞混了,这是触发大量类型不匹配错误的核心原因。咱们一步步拆解问题并修正:
核心问题分析
- 类型签名与内部操作不匹配:你的
attackMM签名声明返回Board,但内部调用的findMinion1、findMinion2都返回Maybe Minion,damageMM返回Maybe (Minion, Minion)——这些都是MaybeMonad下的操作,整个do块的实际返回类型是Maybe Board,和签名要求的Board直接冲突。 - do块内的错误解构:你试图直接从
damageMM的结果里取fst和snd,但damageMM返回的是Maybe (Minion, Minion),不能直接解构,得先在do块里提取完整元组。 - 普通值与Monad值的混用:
killMinion返回的是普通Board,但在Maybe Monad的do块里,需要把它包装成Maybe Board才能保持流程统一。
修正后的attackMM函数
首先我们调整函数的类型签名,让它返回Maybe Board(这更符合Haskell的设计哲学,能明确表达"找不到随从则操作失败"的语义),然后修正do块逻辑:
attackMM :: Name -> Name -> Board -> Maybe Board attackMM n m b = do m1 <- findMinion1 n b -- 从己方战场查找目标随从,返回Maybe Minion m2 <- findMinion2 m b -- 从对方战场查找目标随从,返回Maybe Minion (m1', m2') <- damageMM (Just m1) (Just m2) -- 直接提取damageMM返回的受损随从元组 let b1 = killMinion m1' b -- 处理第一个随从的死亡判定 b2 = killMinion m2' b1 -- 处理第二个随从的死亡判定 return b2 -- 将最终战场状态包装成Maybe返回
可选:强制返回Board的版本(不推荐)
如果你坚持要让attackMM返回Board(会丢失"操作失败"的信息),可以给一个默认值(比如原战场状态):
attackMM :: Name -> Name -> Board -> Board attackMM n m b = case attackMMMaybe n m b of Just newBoard -> newBoard Nothing -> b where attackMMMaybe :: Name -> Name -> Board -> Maybe Board attackMMMaybe n m b = do m1 <- findMinion1 n b m2 <- findMinion2 m b (m1', m2') <- damageMM (Just m1) (Just m2) let b1 = killMinion m1' b b2 = killMinion m2' b1 return b2
修正逻辑说明
- 调整类型签名为
Maybe Board,能准确反映函数的实际行为:找不到指定随从时返回Nothing,操作成功则返回Just Board。 - 在do块里直接提取
damageMM的元组,符合Maybe Monad的使用规则——只有当damageMM返回有效结果时,才会继续执行后续步骤。 - 最后用
return把普通Board包装成Maybe Board,让整个do块的返回类型保持统一。
内容的提问来源于stack exchange,提问作者jack
相关产品推荐
相关产品推荐

