Search code examples
haskelltypeclassreturn-typeadhoc-polymorphismscoped-type-variables

Using return type polymorphism dictated by type classes


I have a class HasFavorite which assigns certain domains with my corresponding favorites.

class HasFavorite domain where
    favorite :: domain

data Animal = Monkey | Donkey
    deriving Show
data Color = Red | Blue
    deriving Show

instance HasFavorite Animal where
    favorite = Donkey

instance HasFavorite Color where
    favorite = Blue

Now, I want to define this:

rant :: (Show d, HasFavorite d) => d -> String
rant x = (show x) ++ "sucks. " ++ (show (favorite :: d)) ++ " is better."

For every invocation of rant x there is a concrete type to which favorite :: d can be resolved. Why can't Haskell do this?

I have tried adding {-# LANGUAGE ScopedTypeVariables #-} but that did not help.


Solution

  • In addition to ScopedTypeVariables, you also need to add a forall d to the type signature of rant:

    rant :: forall d. (Show d, HasFavorite d) => d -> String
    rant x = (show x) ++ " sucks. " ++ (show (favorite :: d)) ++ " is better."
    

    Or you could match on the argument type:

    rant :: (Show d, HasFavorite d) => d -> String
    rant (x :: d) = (show x) ++ " sucks. " ++ (show (favorite :: d)) ++ " is better."
    

    See the GHC manual for all the details.