Keynan
Keynan

Reputation: 1346

why is constructor expected in instance definition in Haskell

Can anyone explain this error:

Syntax error in instance head (constructor expected)

class Nullable v where
  default_val :: v


instance Num a => Nullable a where  -- error reported here
  default_val = 0::a

Thanks

Upvotes: 1

Views: 443

Answers (4)

Marek Sieradzki
Marek Sieradzki

Reputation: 119

There's also another solution: constraint families described here:

http://dorchard.wordpress.com/2011/09/22/constraint-kinds-in-haskell-finally-bringing-us-constraint-families/

class Expr sem where
    constraint Pre sem a
    constant :: Pre sem a => a -> sem a
    add :: Pre sem a => sem a -> sem a -> sem a

instance Expr E where
    constraint Pre E a = Num a
    ...

It says it's available in GHC HEAD or GHC 7.4 (when released).

Upvotes: 0

John L
John L

Reputation: 28097

First off, hackage has you covered.

Secondly, don't write instances of the form

instance OtherClass a => Class a where

they don't work like you want. (YMMV with compilers other than GHC, but I can't see that it's a good idea even then). Presumably your intent is to create several instances, something like:

instance Num a => Nullable a where  -- error reported here
  default_val = 0::a

instance Bounded a => Nullable a where
  default_val = minBound

You can think of type class constraints as an extra argument to a function, like this:

instance Num a => Nullable a where
  default_val = NumDict a -> 0::a

instance Bounded a => Nullable a where
  default_val = BoundedDict a -> minBound

Then ghc actually sees these class instances like this:

instance Nullable a where
  default_val = NumDict a -> 0::a

instance Nullable a where
  default_val = BoundedDict a -> minBound

Now, which instance should the compiler choose? There are two instances that both claim to be valid for all types. So there's a compiler error.

This is a problem even if you one have one type class based instance. Suppose that you have these instances:

instance Num a => Nullable a where
  default_val = 0::a

instance Nullable String where
  default_val = ""

instance Nullable BS.ByteString where
  default_val = BS.empty

The first is still considered valid for all types, so ghc says that it needs the OverlappingInstances extension to use them all. That's not entirely evil. But when you try to make any use of this, before long ghc will require another extension, IncoherentInstances.

Lots of people are afraid to use UndecidableInstances, but that fear is misplaced. The worst that can happen with UndecidableInstances is that compiling won't terminate (but it usually does). IncoherentInstances is the extension which should inspire fear, as it will bring doom upon your code. If GHC says that you have to enable IncoherentInstances, it means you need to change your code.

tl;dr

Don't write instances of the form

instance OtherClass a => Class a where

They don't do what you want.

Upvotes: 8

Thomas M. DuBuisson
Thomas M. DuBuisson

Reputation: 64750

Discussion

Your code isn't valid Haskell. Don't get me wrong - it's in a form commonly seen in the Haskell community and it can be compiled by GHC, but I urge you not to confuse "Haskell" with "Haskell plus all the extensions GHC can offer".

1) You are instantiating a type class using another typeclass as a constraint and no type constructor what-so-ever. In Haskell 2010 you must have a type constructor:

The general form of the corresponding instance declaration is: instance cx′ => C (T u1 … uk) where { d } where k ≥ 0. The type (T u1 … uk) must take the form of a type constructor T applied to simple type variables u1, … uk; furthermore, T must not be a type synonym, and the ui must all be distinct.

The extensions GHC offers here are FlexibleInstances and UndecidableInstances.

2) you explicitly give default_val a type in your instance. This is entirely unnecessary, but if you insist then this too has an extension called ScopedTypeVariables.

The Short

The extensions you need can be enabled either on a file-by-file basis using language pragma:

{-# LANGUAGE FlexibleInstance UndecidableInstances ScopedTypeVariables #-}

Or at the command line of either ghc or ghci (which actually is just a wrapper around ghc):

ghci -XFLexibleInstances -XUnderstandMyIntent

Again, many extensions are GHC-centric. Your code will never run on any other Haskell compiler of note or my name isn't John Meacham.

Upvotes: 1

Dan
Dan

Reputation: 11079

There is a rule in Haskell that the constraints must be "smaller" than the instance itself. I don't exactly understand the theoretical justification behind it, but as a practical matter you can get around it with a newtype.

newtype N a = N a

instance Num a => Nullable (N a) where
    default_val = N 0

GHC also has an option to disable some of these rules. See http://www.haskell.org/ghc/docs/latest/html/users_guide/type-class-extensions.html

Also note that you can't put the ::a in there. It doesn't refer to the same a in the instance declaration, but is considered a universal a, which wouldn't make any sense there.

Upvotes: 1

Related Questions