Reputation: 1346
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
Reputation: 119
There's also another solution: constraint families described here:
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
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
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
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