Search code examples
haskellfunctor

Haskell - Custom functor instance on data type with function constructor


I am having trouble writing my own instance of functor for a custom data type (that I cannot change). The data types are defined as:

data Foo a = Baz String (Qux -> Foo a) | Bar a
data Qux = None | Quux String

My problem is with writing a functor for the Foo type. Specifically, I'm not sure how to properly apply my functor function f to the function in the Foo. I was thinking of somehow calling the function in the constructor, but since I don't have any Qux's available for use, I'm stuck.

instance Functor Foo where
    fmap f (Bar a) = Bar (f a)
    fmap f (Baz s ???) = Baz s (???) -- What goes here?

    -- Clearly, something like this doesn't work
    -- fmap f (Baz s g) = Baz s (f g) 

    -- I've also tried something like this, but I'm not sure where to go from there
    -- fmap f (Baz s (None   -> Bar b)) = Baz s (f b) ???
    -- fmap f (Baz s (Quux x -> Bar b)) = Baz s ???

Solution

  • Let's start by completing the left side of this equation. We can write g to bind your function to a variable.

    fmap f (Baz s g) = Baz s (???)

    Then, we need to fill in the question marks with another function, that takes a Qux and returns a Foo b.

    fmap f (Baz s g) = Baz s (\q -> ???)

    We can only do one thing with q, which is apply g to it.

    fmap f (Baz s g) = Baz s (\q -> g q)

    However, this gives us a Foo a, but we need a Foo b! We don't have a function to do that. We do, however, have f, which takes an a and returns a b. If only there were a way to take a -> b and turn it into Foo a -> Foo b... oh wait, there is, it's called fmap!

    fmap f (Baz s g) = Baz s (\q -> fmap f (g q))

    If you want to write the function in point free notation (https://wiki.haskell.org/Pointfree), you can do this instead.

    fmap f (Baz s g) = Baz s (fmap f . g)