
I'm writing a small unit library to excercise my barely existing Haskell skills. However I can't figure out how to make Haskell accept any type of a specific class. This is what I've got so far: <code> class Unit u where shortName :: u -> String data Meter = Meter instance Unit Meter where shortName u = "m" data UnitValue = UnitValue {uUnit :: Unit u => u, uValue :: Num n => n} </code> Meter is supposed to be a type in the Unit class. UnitValue is supposed to represent unit values regardless of the Unit type. Meter appears to be a subclass of Unit, so far so good: *Units> shortName Meter "m" But I can't get UnitValue to accept Meter as a Unit: *Units> UnitValue Meter 10 <interactive>:1:10: Couldn't match the rigid variable `u' against `Meter' `u' is bound by the polymorphic type `forall u. (Unit u) => u' at <interactive>:1:0-17 Expected type: u Inferred type: Meter In the first argument of `UnitValue', namely `Meter' In the definition of `it': it = UnitValue Meter 10 I strongly suspect that I've got the declaration of UnitValue wrong but I've spent two hours searching the web and trying to get it to work without any success.

Perhaps you want
data UnitValue u n =
(Unit u, Num n) => UnitValue {uUnit :: u, uValue :: n}
On 13/06/05, Adde
I'm writing a small unit library to excercise my barely existing Haskell skills. However I can't figure out how to make Haskell accept any type of a specific class.
This is what I've got so far: <code> class Unit u where shortName :: u -> String
data Meter = Meter
instance Unit Meter where shortName u = "m"
data UnitValue = UnitValue {uUnit :: Unit u => u, uValue :: Num n => n} </code>
Meter is supposed to be a type in the Unit class. UnitValue is supposed to represent unit values regardless of the Unit type.
Meter appears to be a subclass of Unit, so far so good:
*Units> shortName Meter "m"
But I can't get UnitValue to accept Meter as a Unit:
*Units> UnitValue Meter 10
<interactive>:1:10: Couldn't match the rigid variable `u' against `Meter' `u' is bound by the polymorphic type `forall u. (Unit u) => u' at <interactive>:1:0-17 Expected type: u Inferred type: Meter In the first argument of `UnitValue', namely `Meter' In the definition of `it': it = UnitValue Meter 10
I strongly suspect that I've got the declaration of UnitValue wrong but I've spent two hours searching the web and trying to get it to work without any success.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Cale Gibbard
Perhaps you want data UnitValue u n = (Unit u, Num n) => UnitValue {uUnit :: u, uValue :: n}
Thanks! That works... As I understand it this is not using the above mentioned existential types as I'm allowed to use record labels, right? Any chance that someone could write out in english exactly what the above declaration says? I'm trying to fit this in with what I allready know ;) /Adde

Cale Gibbard
Perhaps you want data UnitValue u n = (Unit u, Num n) => UnitValue {uUnit :: u, uValue :: n}
I tried adding UnitValue as an instance of class Show, but I can't figure out how to tell the compiler that u is a Unit and m is a Num (shouldn't it be able to figure that out from the above declaration?): instance Show (UnitValue u m) where show (UnitValue u m) = show m ++ (shortName u) This is the error I'm getting: Could not deduce (Show m) from the context (Show (UnitValue u m)) arising from use of `show' at /Users/adde/Projects/Haskell/units.hs:18:26-29 Probable fix: add (Show m) to the class or instance method `show' In the first argument of `(++)', namely `show m' In the definition of `show': show (UnitValue u m) = (show m) ++ (shortName u) In the definition for method `show' Could not deduce (Unit u) from the context (Show (UnitValue u m)) arising from use of `shortName' at /Users/adde/Projects/Haskell/units.hs:18:37-45 Probable fix: add (Unit u) to the class or instance method `show' In the second argument of `(++)', namely `(shortName u)' In the definition of `show': show (UnitValue u m) = (show m) ++ (shortName u) In the definition for method `show'

On 14/06/05, Adde
Cale Gibbard
writes: Perhaps you want data UnitValue u n = (Unit u, Num n) => UnitValue {uUnit :: u, uValue :: n}
I tried adding UnitValue as an instance of class Show, but I can't figure out how to tell the compiler that u is a Unit and m is a Num (shouldn't it be able to figure that out from the above declaration?):
instance Show (UnitValue u m) where show (UnitValue u m) = show m ++ (shortName u)
You indicate the class restrictions just before the name of the class and type, with the usual implication arrow: instance (Num m, Unit u) => Show (UnitValue u m) where show (UnitValue u m) = show m ++ (shortName u)
This is the error I'm getting:
Could not deduce (Show m) from the context (Show (UnitValue u m)) arising from use of `show' at /Users/adde/Projects/Haskell/units.hs:18:26-29 Probable fix: add (Show m) to the class or instance method `show' In the first argument of `(++)', namely `show m' In the definition of `show': show (UnitValue u m) = (show m) ++ (shortName u) In the definition for method `show'
Could not deduce (Unit u) from the context (Show (UnitValue u m)) arising from use of `shortName' at /Users/adde/Projects/Haskell/units.hs:18:37-45 Probable fix: add (Unit u) to the class or instance method `show' In the second argument of `(++)', namely `(shortName u)' In the definition of `show': show (UnitValue u m) = (show m) ++ (shortName u) In the definition for method `show'
When you get errors like this, there are actually two probable fixes: the one mentioned, to add the class restraints to the method (if you're allowed to, in this case you can't/don't want to), or to add the class restraints to the instance, which is what you want to do. - Cale

For extra fun, notice that you can make declarations like: data (Unit u) => Kilo u = Kilo u instance (Unit u) => Unit (Kilo u) where shortName (Kilo u) = "k" ++ shortName u which behaves in ghci like: *Main> UnitValue (Kilo Meter) 30 30km - Cale

I'm writing a small unit library to excercise my barely existing Haskell skills. However I can't figure out how to make Haskell accept any type of a specific class.
[snip] What you want is a technique called "existential types". The wiki page is here: http://haskell.org/hawiki/ExistentialTypes The problem with existentials is that they are pretty picky about how you use them; I'm pretty sure you can't create a labeled record containing existentials (because the accessor functions aren't allowed to exist). You have to pattern match to get at the encapsulated value. Also, once you have done the pattern match on the "UnitValue," you can only use polymorphic functions on the pattern variables. The following does what I think you want. {-# OPTIONS -fglasgow-exts #-} class Unit u where shortName :: u -> String data Meter = Meter instance Unit Meter where shortName u = "m" data UnitValue = forall u n. (Unit u,Num n) => UnitValue u n main = let x = UnitValue Meter 10 in case x of UnitValue unit magnitude -> putStrLn $ (show magnitude)++(shortName unit)

What you want is a technique called "existential types". The wiki page is here: http://haskell.org/hawiki/ExistentialTypes
Thanks, I stumbled upon Existential Types earlier but ofcourse I tried to use them with labeled records.

While we're at it, I tried adding a class Length in between Unit and Meter, like this: class Unit u where shortName :: u -> String class (Unit u) => Length u instance Length Meter where shortName u = "m"
From the information I can find on the web subclassing should include all of the methods in the superclasses but I get this error:
`shortName' is not a (visible) method of class `Length'

On 14/06/05, Adde
While we're at it, I tried adding a class Length in between Unit and Meter, like this:
class Unit u where shortName :: u -> String
class (Unit u) => Length u
instance Length Meter where shortName u = "m"
From the information I can find on the web subclassing should include all of the methods in the superclasses but I get this error:
`shortName' is not a (visible) method of class `Length'
It's saying that shortName isn't a method of the class Length, which is right, it's a method of the class Unit, so you should put it in the Unit instance rather than in the Length instance. The declarations in an instance of a class C may contain bindings only for the class methods of C. The class methods of C are exactly those whose type signatures are given in the class declaration of C (which may not overlap with other class declarations or top level bindings).
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
participants (3)
-
Adde
-
Cale Gibbard
-
robert dockins