Ceilvia C
Ceilvia C

Reputation: 53

How to write fmap for a Functor that has a function in it's data type definition?

I have data defined as below:

data FGM a = Pure a | GMAction Integer Integer (PlayerMsg -> FGM a)
data PlayerMsg = Guess Integer | Surrender
    deriving (Eq, Show)

FGM represents a number guessing game where the 2 integers are the upper and lower bounds, a is the value to be returned in the end, and playermsg is the guess that the player makes. I would like to make FGM a Functor, so I'm trying to define a fmap for it. Problem is I don't know how do deal with the (PlayerMsg -> FGM a) part of FGM.

From my understanding of the testcases given, for fmap g (someFGM), g should only be applied to Pure, if it's GMAction, fmap should use PlayerMsg and generate the next FGM until it reaches a Pure.

This is what I've tried:

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

But when I try to run test on this I get this error:

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:...

I've also tried

fmap g (GMAction upper lower thing) = GMAction upper lower (fmap g thing)

and got the same error.

I tried to search for examples with data that has a function as parameter like PlayerMsg -> FGM a, but can't find anything. this is kind of similar but didn't work for me(it's my first failed example). Can someone help me define this fmap or point me at where to learn about this?

Upvotes: 1

Views: 182

Answers (2)

Daniel Wagner
Daniel Wagner

Reputation: 153332

GHC's built-in rules for deriving Functor are enough to handle simple cases like this.

{-# LANGUAGE DeriveFunctor #-}
data FGM a = Pure a | GMAction Integer Integer (PlayerMsg -> FGM a) deriving Functor
data PlayerMsg = Guess Integer | Surrender
    deriving (Eq, Show)

Upvotes: 4

bradrn
bradrn

Reputation: 8477

Try fmap g (GMAction upper lower thing) = GMAction upper lower ((fmap g) . thing). Note the function composition; this is necessary as you need to fmap over the result of the function.

Upvotes: 5

Related Questions