Multiparameter classes in HUGS and GHC
I've trying to understand better how to use multiparameter classes, and in particular the things that can be declared as instances. I've consulted the following: [1] http://www.haskell.org/onlinereport/decls.html#sect4.3.2 [2] http://www.haskell.org/ghc/docs/latest/html/users_guide/type-extensions.html... (particularly 7.3.5.1 item 3) [3] http://research.microsoft.com/Users/simonpj/Papers/type-class-design-space/ [4] http://cvs.haskell.org/Hugs/pages/hugsman/exts.html (section 7.1) From my reading, it seems that while strict Haskell 98 does not permit type expressions or synonyms to be declared as class instances, both GHC and HUGS claim to relax this restriction (presumably following the analysis in [3]). My problem is that I can't get HUGS to accept a type expression or synonym to be declared as an instance of a (multiparameter) class; I'm getting the error "Illegal type in class constraint". After some wrestling with the system, I have managed to figure how to declare instances that use type constructors. I feel I may be missing something blindingly obvious. My spike code is below: the uncommented sections compile OK, but the commented-out sections do not. #g -- [[ class (Eq k, Show k) => Pair a k v where newPair :: (k,v) -> a k v getPair :: a k v -> (k,v) newtype MyPair1 k v = P1 (Int,String) instance Pair MyPair1 Int String where newPair (x,y) = P1 (x,y) getPair (P1 (x,y)) = (x,y) data MyPair2 k v = P2 Int String instance Pair MyPair2 Int String where newPair (x,y) = P2 x y getPair (P2 x y) = (x,y) data (Eq a, Show a) => MyPair3 a b = P3 a b instance Pair MyPair3 Int String where newPair (x,y) = P3 x y getPair (P3 x y) = (x,y) {- -- The following DO NOT work because instances -- "must take the form of a type constructor T applied -- to simple type variables" (though this may be relaxed -- in the multiparameter case: see [1]). -- -- Apparently, GHC *does* allow this, though HUGS -- apparently does not, though it does claim to [2]. -- -- [1] http://research.microsoft.com/Users/simonpj/Papers/type-class-design-space/ -- -- [2] http://cvs.haskell.org/Hugs/pages/hugsman/exts.html (section 7.1) -} type MyPair4 k v = (k,v) {- instance Pair (Int,String) Int String where newPair = id getPair = id instance Pair (MyPair4 Int String) Int String where newPair = id getPair = id instance Pair (MyPair4 k v) Int String where newPair = id getPair = id -} ]] I'm using the November 2002 release of HUGS with Hugs extensions enabled: [[ Current settings: +fewuiRWX -stgGl.qQkoOIHTN -h250000 -p"%s> " -r$$ -c40 Search path : -P{Hugs}\lib:{Hugs}\lib\exts:{Hugs}\lib\win32:{Hugs}\lib\hugs; {Hugs}\libraries\HUnit-1.0 Project Path : Source suffixes : -S.hs;.lhs Editor setting : -E"C:\\Program Files\\TextPad 4\\TextPad.exe" Preprocessor : -F Compatibility : Hugs Extensions (-98) ]] ------------------- Graham Klyne <GK@NineByNine.org> PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E
Graham Klyne wrote:
class (Eq k, Show k) => Pair a k v where newPair :: (k,v) -> a k v getPair :: a k v -> (k,v)
type MyPair4 k v = (k,v)
instance Pair (Int,String) Int String where newPair = id getPair = id
The kinds are wrong here. `Pair` takes as its first argument a type constructor of kind: * -> * -> *. The following works (with appropriate extensions enabled): instance Pair (,) Int String where newPair = id getPair = id
instance Pair (MyPair4 Int String) Int String where newPair = id getPair = id
Again the kinds are wrong. However, you can't make a Pair instance out of MyPair4 because the latter is a `type` rather than `newtype` or `data`. Hope this helps. Dean
At 14:45 30/04/2003 -0400, Dean Herington wrote:
Again the kinds are wrong. However, you can't make a Pair instance out of MyPair4 because the latter is a `type` rather than `newtype` or `data`.
Hope this helps.
Yes, very much, thank you. If I now have this right, it's the distinction between a parametric polymorphic type and an algebraic type constructor that I had failed to properly appreciate. Now I'm alerted to it, I don't know why I didn't realize sooner that something there was wrong. I discover that I can also use: [[ type MyPair5 = (,) instance Pair MyPair5 Int String where newPair = id getPair = id ]] though I'm not sure how MyPair5 is interpreted as a type synonym ;-) There's a small matter that still puzzles me a little. In: [[ data (Eq a, Show a) => MyPair3 a b = P3 a b instance Pair MyPair3 Int String where newPair (x,y) = P3 x y getPair (P3 x y) = (x,y) ]] (which seems OK), "Pair3" is a type _expression_ of kind (* -> * -> *), the corresponding _constructor_ for which is P3. Yet, according to [1], "(,)" is a type _constructor_. I guess there may be some terminological crossover here as type constructors often use the same name as the corresponding type expression? [1] http://haskell.org/onlinereport/decls.html#sect4.1.2 #g ------------------- Graham Klyne <GK@NineByNine.org> PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E
In article <5.1.0.14.2.20030430182613.00ba1dc8@127.0.0.1>, Graham Klyne <gk@ninebynine.org> wrote:
class (Eq k, Show k) => Pair a k v where newPair :: (k,v) -> a k v getPair :: a k v -> (k,v)
I would consider one of these instead: class Pair1 a where newPair1 :: (Eq k, Show k) => (k,v) -> a k v getPair1 :: (Eq k, Show k) => a k v -> (k,v) class (Eq k, Show k) => Pair2 p k v | p -> k,v where newPair2 :: (k,v) -> p getPair2 :: p -> (k,v) Pair2 is more general than Pair, for instance: data CharBoolPair = MkCharBoolPair Char Bool instance Pair2 CharBoolPair Char Bool where newPair2 (c,b) = MkCharBoolPair c b getPair2 (MkCharBoolPair c b) = (c,b) CharBoolPair cannot be made an instance of your Pair (since it has kind "*"). Pair is more general than my Pair1, there may be type constructors that are instances of Pair but not Pair1; but I can't imagine them turning up in well-written code. -- Ashley Yakeley, Seattle WA
participants (3)
-
Ashley Yakeley -
Dean Herington -
Graham Klyne