Typeclass question

Hi all, I want to make all types that are instances of Integral instances of another type class, i.e: {-# LANGUAGE FlexibleInstances #-} class Intable a where toInt :: a -> Int instance (Integral a) => Intable a where toInt l = fromIntegral l However this gives the following error that I don't understand: q.hs:6:0: Constraint is no smaller than the instance head in the constraint: Integral a (Use -XUndecidableInstances to permit this) In the instance declaration for `Intable a' Can anyone offer insight on thie error? Also, is there perhaps a different way to do what I want to do? Thanks, Patrick -- ===================== Patrick LeBoutillier Rosemère, Québec, Canada

Hi Patrick As you guessed, adding UndecidableInstances pragma would make it work. Loosely speaking, the type of your instance 'contains' all the types that the class can use anyway. Hopefully, someone more learned than me will give a proper definition and add an explanation of the Paterson Conditions. http://www.haskell.org/ghc/docs/latest/html/users_guide/type-class-extension... But why not just a function: toInt :: Integral a => a -> Int toInt = fromIntegral Of course just a function won't be ideal if you were wanting to have a special instance say for Integer and all other instances to use the general version. There's more to say about this in the context of Generics, but that's a somewhat advanced topic... Best wishes Stephen

On Tue, Dec 01, 2009 at 10:48:50AM -0500, Patrick LeBoutillier wrote:
Hi all,
I want to make all types that are instances of Integral instances of another type class, i.e:
{-# LANGUAGE FlexibleInstances #-}
class Intable a where toInt :: a -> Int
instance (Integral a) => Intable a where toInt l = fromIntegral l
This doesn't mean what you think it means. To do instance selection, (GHC at least) only looks at the part AFTER the =>. So instead of meaning "every type which is an instance of Integral should also be an instance of Intable", it actually means "every type is an instance of Intable; and oh yes, they had better be an instance of Integral too". This can make a big difference. For example, this may look fine, but it is not legal: instance (Integral a) => Intable a where toInt l = fromIntegral l instance (Fractional a) => Intable a where toInt l = round l This looks like it should be OK as long as we never use a type which is an instance of both Integral and Fractional (which is not likely). However, these instances are actually overlapping since the part before the => is not considered when deciding which instance to pick for a particular type. This also hints at an explanation for the error you got. When resolving the use of a type class method, GHC looks at the structure of the type in order to pick a type class instances to use. Once it has chosen an instance (by comparing the type to the part of the instance declaration to the right of the =>), it then considers any additional constraints generated by the left-hand side of the =>, and needs to choose a type class instance for each of those, and so on recursively. The danger is that this process might not terminate; in order to (conservatively) guard against this, GHC requires that any types mentioned on the left-hand side of the => are structurally smaller than types on the right-hand side; this ensures that the process will eventually terminate since types are finite. If you want to disable this check (and therefore introduce the possibility of an inifnitely recursing type checker) you can enable UndecidableInstances --- which isn't really as bad as some people make it out to be, but best avoided unless you really understand why you want it. It's hard to suggest what to do instead without knowing more about what you are specifically trying to do (it seems that your example was just a toy example to illustrate the problem), but you might consider using newtype wrappers. -Brent
participants (3)
-
Brent Yorgey
-
Patrick LeBoutillier
-
Stephen Tetley