Search code examples
haskellpolymorphismfunctor

Haskell fmap over custom data type


In my project I have a few data types that look like this

data StructureA = StructureA [Int] Bool Int
data StructureB = StructureB [String] String

My goal is to map functions over arrays contained inside instances of such datatypes

inst = StructureA [1,1,1] True 0
fmap (+1) inst -- [2,2,2]

My initial solution solution looks like this

instance Functor StructureA where
    fmap (StructureA arr _ _) = fmap arr

However, I get kind mismatch error.

Question is how I can declare a function that can be polymorphically applied over such data structures?


Solution

  • You can only declare a Functor instance over a parameterized type (* -> * to be precise): a type that still needs an extra (and exactly one) type parameter.

    So first we will need to introduce a type parameter. Even if you never plan to use something else than Ints, we can easily abstract that away with:

    data Structure a = Structure [a] Bool Int

    We can for example declare the StructureA as a type synomym:

    type StructureA = Structure Int

    Now we can make it a Functor instance, by writing:

    instance Functor Structure where
        fmap f (Structure as b c) = ...

    Note that we here did not write (Structure a), but Structure, since - like we already said - fmap has the freedom to change the type over which the collection works: the f function can have for example type Int -> Char to convert a Structure Int to a Structure Char.

    Now we still need to implement fmap. fmap has type fmap :: Functor f => (a -> b) -> f a -> f b so that means it takes a function, and in this case a Structure a, and constructs a Structure b. Based on your question (and the design decisions we have made), the only part we can map is the first parameter, so we construct a new Structure, where the second parameter is the result of an fmap f, but then over the second parameter, so:

    instance Functor Structure where
        fmap f (Structure as b c) = Structure (fmap f as) b c