我有以下代码(应该是对炉石的游戏进行建模)。
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函数之外,所有函数都按预期工作,这会导致许多类型不匹配错误。我已经盯着代码一段时间了,虽然我确定这是显而易见的,我可以用一双新眼睛来看它。 :)
答案 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
块中有do
,e :: a
和f :: 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' b
但killMinion 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')
。