Typeclass contexts in datatypes are now regarded as a not so useful feature. The problem is that the following does not compile:
foo :: Units a -> a
foo (Units x _) = x+x
This intuitively should compile, since the Units a
argument can only be constructed for a type a
satisfying Num a
. So, on destruction (pattern matching) one should be able to access the Num a
instance. However this is not the case, and a Num a
must be counterintuitively provided on destruction as well:
foo :: Num a => Units a -> a
foo (Units x _) = x+x
The standard suggestion is therefore to remove the constraint Num a
from the Units a
datatype declaration, and add it instead to every function involving Units a
.
Another option is to enable GADTs and change the datatype to:
data Units a where
Units :: Num a => a -> SymbolicManip a -> Units a
This does the "right" thing: a Num a
instance is required to construct a value, and is instead provided on destruction. In this way, the first foo
declaration above will be well-typed.
I almost forgot the "quick & dirty" option, which is to enable the obsolescent datatype context feature: this is done by adding at the beginning of your file the line
{-# LANGUAGE DatatypeContexts #-}
Still, I would rather modify the code than to enable this language extension.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…