我的数据定义如下:
data FGM a = Pure a | GMAction Integer Integer (PlayerMsg -> FGM a)
data PlayerMsg = Guess Integer | Surrender
deriving (Eq, Show)
FGM代表一个猜数字游戏,其中2个整数是上下边界,a是最后要返回的值,playermsg是玩家进行的猜测。
我想将FGM用作函子,所以我正在尝试为其定义fmap。问题是我不知道如何处理FGM的(PlayerMsg -> FGM a)
部分。
根据我对给定的测试用例的理解,对于fmap g
(someFGM),g应该仅应用于Pure
,如果它是GMAction
,则fmap应该使用PlayerMsg
并且生成下一个FGM,直到达到Pure
。
这是我尝试过的:
instance Functor FGM where
fmap g (Pure a) = Pure (g a)
fmap g (GMAction upper lower thing) = GMAction upper lower (fmap g (\x -> case (thing x) of
Pure a -> Pure a
GMAction u l t -> GMAction u l t))
但是当我尝试对此进行测试时,出现此错误:
Occurs check: cannot construct the infinite type:
b ~ FGM b
Expected type: PlayerMsg -> FGM b
Actual type: PlayerMsg -> b
In the third argument of 'GMAction', namely '(fmap g (\x -> case (thing x) of
Pure a -> Pure a
GMAction u l t -> GMAction u l t))'
In the expression:...
我也尝试过
fmap g (GMAction upper lower thing) = GMAction upper lower (fmap g thing)
并遇到相同的错误。
我试图用数据作为参数来搜索示例,这些数据具有像PlayerMsg -> FGM a
这样的参数功能,但是找不到任何东西。 this有点相似,但对我没用(这是我第一个失败的示例)。有人可以帮我定义这个fmap或指向我在哪里学习吗?
答案 0 :(得分:5)
尝试fmap g (GMAction upper lower thing) = GMAction upper lower ((fmap g) . thing)
。注意功能组成;这是必要的,因为您需要fmap
在函数的结果上。
答案 1 :(得分:4)
GHC推导Functor
的内置规则足以处理这样的简单情况。
{-# LANGUAGE DeriveFunctor #-}
data FGM a = Pure a | GMAction Integer Integer (PlayerMsg -> FGM a) deriving Functor
data PlayerMsg = Guess Integer | Surrender
deriving (Eq, Show)