Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functors in Haskell: showing the value of an item of the type of the type parameter

Tags:

haskell

GHC does not know how to show Type a.

data FunctorExample a = FunctorExample { val1 :: a, 
                                         val2 :: String
                                        } deriving (Show) 

instance Functor FunctorExample where
    fmap f (FunctorExample x y) = FunctorExample (f x) (y ++ " " ++ show x)

I've tried a number of things, including: setting a type constraint in data (now deprecated), and using {-# LANGUAGE InstanceSigs #-} to add a constraint for fmap and adding the type signature suggested below, with no success (though it's possible my type signature was flawed...).

    * No instance for (Show a) arising from a use of `show'
      Possible fix:
        add (Show a) to the context of
          the type signature for:
            fmap :: forall a b.
                    (a -> b) -> FunctorExample a -> FunctorExample b

Is there no standard way of constraining a to be a Show instance? It happens to always be an Int in my usage.

like image 787
Learning... Avatar asked Dec 03 '20 06:12

Learning...


Video Answer


1 Answers

Disclaimer: Forgive me if I make any blunders or approach the question differently, I'm also a Haskell learner myself.

The first thing I'd like to point out is that your definition fmap does not comply with the two functor laws. These laws exist so that "the behaviour of fmap remains predictable".

The first law states that fmap id functor should be no different from id functor (i.e. fmap id = id). Just eyeballing the definition, we can see that this:

fmap id (FunctorExample x y) = FunctorExample (id x) (y ++ ...)

...isn't going to fly, since the value of the second y is prone to change.

The second law states that fmap (f . g) = fmap f . fmap g. I'll leave it to you as an exercise to check if it complies or not.

What I'll suggest here is to use a different function instead, then there's no burden of complying with functor laws. This way, you can use type-class constraints.

propagate :: Show a => (a -> b) -> FunctorExample a -> FunctorExample b
propagate f (FunctorExample x y) = FunctorExample (f x) (y ++ " " ++ show x)

Now, maybe you had a particular purpose in mind with fmap. I'm not entirely sure. Maybe you meant to use FunctorExample in other functions which take functors. (I'm guessing so by the name.) If so, consider redesigning the fmap definition so that it complies with the functor laws.

To clarify, constraining the type of fmap is not possible.

like image 146
TrebledJ Avatar answered Nov 15 '22 05:11

TrebledJ