2

I am trying to define Int as an instance of my type class Add. I wanted to define my own operator +++, which should be overloaded on integers and strings. My goal was to be able to add integers and concatenate strings with the same operator. Therefore i created the type class Add with the instances Int and [char]:

class Add a where
    (+++) :: a -> a -> a

instance Add Int where
    x +++ y = x + y

instance Add [char] where
    x +++ y = x ++ y

Problem: When evaluating the expression 1 +++ 2, GHCi gives me the following error message:

<interactive>:9:1: error:
    • Ambiguous type variable ‘a0’ arising from a use of ‘print’
      prevents the constraint ‘(Show a0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a0’ should be.
      These potential instances exist:
        instance Show Ordering -- Defined in ‘GHC.Show’
        instance Show Integer -- Defined in ‘GHC.Show’
        instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
        ...plus 22 others
        ...plus 18 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In a stmt of an interactive GHCi command: print it

But when defining Integer as an instance of Add

instance Add Integer where
    x +++ y = x + y

GHCi can evaluate 1 +++ 2 to 3 and i don't get an error.

Question: Why is it not working, when using Int as an instance? What is the difference in using Int or Integer?

3
  • 2
    The problem isn't that it doesn't work, the problem is that it could work in more than one way and the compiler doesn't know which one you want. Commented Jun 2, 2020 at 10:22
  • i just found a similar question to this with the same problem: stackoverflow.com/questions/16824047/… Commented Jun 2, 2020 at 10:29
  • 2
    Kind of orthogonal to your question, but: please don't write instance Add [char]. This happens to work, but for a misleading reason that I'm not sure you're aware of: char, being lowercase, is a type variable. I.e. this instance actually works for lists of any type, not just character ones. To make this clear, simply write it instance Add [a]. —Or, if you really want this instance to be Char-specific, write instance Add [Char] (w/ -XFlexibleInstances) or instance (c ~ Char) => Add [c] (requires -XGADTs or -XTypeFamilies). [These behave differently!] Commented Jun 3, 2020 at 11:39

1 Answer 1

6

Given that it works for Integer but not Int, I'm fairly sure this is due to "type defaulting".

In GHCi (and to a lesser extent in compiled code), if an expression has an ambiguous type, the compiler tries several "default types", which of which is Integer (but not Int). That's almost certainly where the difference is coming from.

I suspect if you add :: Int to the end of your expression, it will execute just fine. The problem isn't that there's a type error, it's that more than one type potentially fits, and the compiler isn't sure which one you intended.

I've never tried this, but I believe you can change the defaults by saying something like default (Int, Double). (Usually it's default (Integer, Double).) I think that's the right syntax; not 100% sure.

There's a bit about this in the GHCi manual: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html#type-defaulting-in-ghci

Also the Haskell Report: https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-750004.3 (Section 4.3.4)

Sign up to request clarification or add additional context in comments.

2 Comments

yes, thank you. Adding :: Int at the end of 1 +++ 2 would work
FWIW, I'm rather fond of default (), because I generally don't want any defaulting. But default to Int is pretty reasonable if you want to use (^) a lot.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.