Search code examples
haskellfunctional-programmingfunctoroption-typecontravariant

Learning how to use contramap when is expected (a -> Maybe b) instead of (a -> b) as the first parameter (Haskell)


I'm studying Haskell and I was asked to solve this exercise:

Implement a new data type named NovoPred that should have a value constructor with the same name. Also it should have a field named runNovoPred with type Maybe a -> Bool Then, create an Functor Contravariant instance for type NovoPred

In order to solve this exercise, I've made this solution:

module Oitavo where

import           Data.Functor.Contravariant

newtype NovoPred a =
  NovoPred
    { runNovoPred :: Maybe a -> Bool
    }

instance Contravariant NovoPred where
    contramap y (NovoPred x) = NovoPred (x . y)

As you may notice, this solution doesn't work at all. Contramap needs to have this structure: (a -> b) -> f b -> f a, the problem is that x function expects to receive a value that looks like Maybe b and it is actually receiving a value b because that is what y function returns. Therefore, it is impossible to do x . y, because x expects to receive a value that doesn't match with what y is actually returning.

So, I think I need a way to make y function return a value of type Maybe b. Unfortunately, I don't have a clue on how to do it since contramap expects to receive something like a -> b as first parameter instead of something like a -> Maybe b (that's what I need). Could you give me a hand with that?


Solution

  • If you have a function y :: a -> b and you need to convert a Maybe a to a Maybe b, you can just fmap over Maybe:

    contramap y (NovoPred x) = NovoPred (x . fmap y)