使用建模炉石的类型不匹配

时间:2018-05-15 19:08:38

标签: haskell types

我有以下代码(应该是对炉石的游戏进行建模)。

import Control.Monad
import Data.List

type Attack = Int
type HP = Int
type Name = String
type Minion = (Name,Attack,HP) 

type Board = ([Minion],[Minion])

attackMM :: Name -> Name -> Board -> Board
attackMM n m b = do {m1 <- findMinion1 n b;
                     m2 <- findMinion2 m b;
                     m1'<- fst (damageMM (Just m1) (Just m2));
                     m2'<- snd (damageMM (Just m1) (Just m2));
                     b' <- killMinion m1' b;
                     killMinion m2' b'}


killMinion :: Minion -> Board -> Board
killMinion m@(_,_,hp) b@(xs,ys) = if elem m xs && hp <= 0 then ((delete m xs),ys)
                                  else if elem m ys && hp <= 0 then (xs,(delete m ys))
                                  else b

damageMM :: Maybe Minion -> Maybe Minion -> Maybe (Minion,Minion)
damageMM Nothing _ = Nothing
damageMM _ Nothing = Nothing
damageMM (Just (n1,a1,hp1)) (Just (n2,a2,hp2)) = Just ((n1,a1,hp1-a2),(n2,a2,hp2-a1)) 

findMinion1 :: Name -> Board -> Maybe Minion
findMinion1 n ([],_) = Nothing
findMinion1 n ((x:xs),ys) = if n == fst3 x then Just x
                               else findMinion1 n (xs,ys) 


findMinion2 :: Name -> Board -> Maybe Minion
findMinion2 n (_,[]) = Nothing
findMinion2 n (xs,(y:ys)) = if n == fst3 y then Just y
                               else findMinion2 n (xs,ys) 


fst3 :: (a,b,c) -> a
fst3 (a,_,_) = a

trd3 :: (a,b,c) -> c
trd3 (_,_,c) = c

除了attackMM函数之外,所有函数都按预期工作,这会导致许多类型不匹配错误。我已经盯着代码一段时间了,虽然我确定这是显而易见的,我可以用一双新眼睛来看它。 :)

2 个答案:

答案 0 :(得分:0)

findMinion1会返回Maybe Minion,并且您使用Just m1将其换行,然后该类型为Maybe (Maybe Minion),但damageMM需要Maybe Minion }。

删除Just m1(和Just m2)应该适用于damageMM的调用

答案 1 :(得分:0)

您对do Maybe使用Monad表示法。 因此,如果e <- f块中有doe :: af :: Maybe a

拨打m1 <- findMinion1 n b;时,您可以正确使用此功能。

但是无需再次m1再次Just。{/ p>

因此,请将damageMM的类型更改为Minion -> Minion -> Maybe (Minion,Minion),不要将其包含在Just中。

然后你会有类似m1'<- fst (damageMM m1 m2)的内容,但这仍然是错误的,因为damageMM m1 m2 :: Maybe (Minion,Minion)fst :: (a,b) -> a。类型不匹配。但是m1' :: (Minion,Minion),所以你想要改为fst

m1' <- fst (damageMM m1 m2);
let fm1' = fst m1'    

然后你将b' <- killMinion fm1' bkillMinion fm1' b :: Board。您应该知道<-只是使用bind:(>>=) :: m a -> (a -> m b) -> m b的很好的语法。在do区块中m = Maybe。在这种情况下,您使用<-从maybes中“拉”出值,而不是通常将变量赋给表达式。 let就是你想要的:

let b' = killMinion m1' b

最后,您希望返回killMinion m2' b'作为最终值。但你不能因为你从Maybe Monad返回,所以你必须返回Maybe

因此,您必须更改类型签名:attackMM :: Name -> Name -> Board -> Maybe Board并将您的返回值重新设置为:return (killMinion m2' b')