如何为在数据类型定义中具有功能的Functor编写fmap?

时间:2019-03-24 02:11:40

标签: haskell

我的数据定义如下:

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或指向我在哪里学习吗?

2 个答案:

答案 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)