Search code examples
haskellfunctor

Using functor in haskell


I've a World datatype that is defined this way:

     data World = World
    { resolution :: (Int, Int)
    , direction :: Snake_direction
    , snake_scale :: Int
    , snake :: [(Int, Int)]
    , isStuck :: Bool
    , gen :: R.StdGen
    , food :: (Int, Int)
    , superFood :: (Int, Int)
    } deriving (Read, Show) 

and I want to use a functor that uses fmap over the snake list which is a paramter of the world datatype. I'm struggling with functor syntax

instance Functor (World) where
    fmap f (World) = World {fmap f snake}

but the compiler says

error: parse error on input ‘f’

Solution

  • If we inspect the Functor type class, we see:

    class Functor (f :: * -> *) where
      fmap :: (a -> b) -> f a -> f b
      (<$) :: a -> f b -> f a
      {-# MINIMAL fmap #-}

    So the kind of f should be * -> *, a type with a type parameter. This is not the case here, so we can not declare World an instance of Functor. Since the user can use any function f :: a -> b to map a World a to a World b, but there is no World a at all.

    If you still want to make it a Functor, we can first "upgrade" the World type such that it has a type parameter:

    data World a = World
        { resolution :: (Int, Int)
        , direction :: Snake_direction
        , snake_scale :: Int
        , snake :: [(a, a)]
        , isStuck :: Bool
        , gen :: R.StdGen
        , food :: (Int, Int)
        , superFood :: (Int, Int)
        } deriving (Read, Show)

    then we can define an fmap as follows:

    instance Functor World where
        fmap f w = w {snake = fmap (\(x,y) -> (f x, f y)) (snake w)}

    or if you want to fmap over the snake directly, and not over the coordinates of the snake:

    data World a = World
        { resolution :: (Int, Int)
        , direction :: Snake_direction
        , snake_scale :: Int
        , snake :: a
        , isStuck :: Bool
        , gen :: R.StdGen
        , food :: (Int, Int)
        , superFood :: (Int, Int)
        } deriving (Read, Show)

    then we can define an fmap as follows:

    instance Functor World where
        fmap f w = w {snake = f (snake w)}