Query regarding Type classes

Hello folks, Im kinda new to haskell. Ive only been fiddling around with it for bout 3 - 4 weeks now. And for the life of me... i cant seem to figure out why this doesnt work : class Foo a where fooFunc :: a -> Int data FooData = FData instance Foo FooData where fooFunc _ = 10 class Bar a where barFunc :: (Foo b) => a -> b -> Int data BarData = BData instance Bar BarData where barFunc _ FData = 20 When I compile I get this : Couldn't match expected type `b' against inferred type `FooData' `b' is a rigid type variable bound by the type signature for `barFunc' at Sample.hs:16:20 In the pattern: FData In the definition of `barFunc': barFunc _ FData = 20 In the definition for method `barFunc' Think Im missing something really big... Could somebody kindly help me out here... Regards Arun Could so

Step 1: Forget everything you know about OO classes, then try again :)
2008/10/13 Arun Suresh
class Foo a where fooFunc :: a -> Int
data FooData = FData
instance Foo FooData where fooFunc _ = 10
So far so good.
class Bar a where barFunc :: (Foo b) => a -> b -> Int
So now, barFunc advertises "for any type a which is in the Bar typeclass, and any type b which is in the Foo typeclass, I can give you a function from a to b to Int". You can make an implementation of this that has different functionality based on "a", but it needs to be polymorphic in "b", taking any type "b" which is a member of Foo.
data BarData = BData
instance Bar BarData where barFunc _ FData = 20
Uh oh! FData is of type FooData! But we just advertised that we could take *anything* which is in the typeclass Foo, which can include any number of other types. It doesn't matter that FooData is the only declared member at this point. What that means is that if you want to do anything with the second argument, you can only use functions that accept any type which is a member of the Foo class. Right now that just means generically polymorphic functions (id, const, etc.), and the fooFunc function inside the "Foo" typeclass. For example, this declaration would work: instance Bar BarData where barFunc _ f = 10 + fooFunc f
When I compile I get this : Couldn't match expected type `b' against inferred type `FooData' `b' is a rigid type variable bound by the type signature for `barFunc' at Sample.hs:16:20 In the pattern: FData In the definition of `barFunc': barFunc _ FData = 20 In the definition for method `barFunc'
The compiler is just telling you what I just told you: barFunc says that it should take any type "b", but the pattern FData constrains the argument to be a FooData.
Think Im missing something really big... Could somebody kindly help me out here...
I recommend reading http://www.haskell.org/haskellwiki/OOP_vs_type_classes -- ryan

Hello Ryan..
On Mon, Oct 13, 2008 at 3:33 PM, Ryan Ingram
Step 1: Forget everything you know about OO classes, then try again :)
you seem to have read my mind [:)].. i actaually hit upon this issue while trying to "transcode" some C++ to Haskell..
2008/10/13 Arun Suresh
: class Foo a where fooFunc :: a -> Int
data FooData = FData
instance Foo FooData where fooFunc _ = 10
So far so good.
class Bar a where barFunc :: (Foo b) => a -> b -> Int
So now, barFunc advertises "for any type a which is in the Bar typeclass, and any type b which is in the Foo typeclass, I can give you a function from a to b to Int". You can make an implementation of this that has different functionality based on "a", but it needs to be polymorphic in "b", taking any type "b" which is a member of Foo.
data BarData = BData
instance Bar BarData where barFunc _ FData = 20
Uh oh! FData is of type FooData! But we just advertised that we could take *anything* which is in the typeclass Foo, which can include any number of other types. It doesn't matter that FooData is the only declared member at this point. What that means is that if you want to do anything with the second argument, you can only use functions that accept any type which is a member of the Foo class. Right now that just means generically polymorphic functions (id, const, etc.), and the fooFunc function inside the "Foo" typeclass.
For example, this declaration would work:
instance Bar BarData where barFunc _ f = 10 + fooFunc f
When I compile I get this : Couldn't match expected type `b' against inferred type `FooData' `b' is a rigid type variable bound by the type signature for `barFunc' at Sample.hs:16:20 In the pattern: FData In the definition of `barFunc': barFunc _ FData = 20 In the definition for method `barFunc'
The compiler is just telling you what I just told you: barFunc says that it should take any type "b", but the pattern FData constrains the argument to be a FooData.
Think Im missing something really big... Could somebody kindly help me out here...
I recommend reading http://www.haskell.org/haskellwiki/OOP_vs_type_classes
Thanks... Arun
-- ryan

On Mon, Oct 13, 2008 at 11:18 AM, Arun Suresh
data Point = Pt { x :: Float, y :: Float } deriving Show data Drawable = Rectangle Point Point | Circle Point Float
render :: Drawable -> IO () render (Rectangle p1 p2) = putStrLn (concat ["Rectangle from ", show p1, " to ", show p2, "."]) render (Circle center radius) = putStrLn (concat ["Circle at ", show center, " with radius ", show radius, "."])
This inverts the control from the OO structure; in the OO the interface is centralized and the data is spread throughout the source. In the pattern-matching style, the data is centralized (in the ADT) but the interface can be spread out. For example, to add a new function "area()" to Drawable, in the OO style you have to add it to Drawable and put an implementation into every class that descends from Drawable, modifying all those modules. But in Haskell you could declare a new function in one place:
area :: Drawable -> Float area (Rectangle p1 p2) = abs (x p2 - x p1) * abs (y p2 - y p1) area (Circle _ r) = pi * r * r
On the other hand, adding new data to Rectangle or Circle requires changing all the pattern matches spread throughout the source, which is somewhat annoying. So there are benefits of both styles. It's possible to emulate the OO style in Haskell, using existential types, but it is a lot harder. It's easier to stick with what the language is good at! :) -- ryan

On Mon, Oct 13, 2008 at 4:08 PM, Ryan Ingram
On Mon, Oct 13, 2008 at 11:18 AM, Arun Suresh
wrote: ] you seem to have read my mind [:)].. i actaually hit upon this issue while ] trying to "transcode" some C++ to Haskell.. (literate haskell post, save it into "draw.lhs" and you can load it in ghci!)
What you usually want when you have some "closed world" OO class hierarchy is to replace the hierarchy with an ADT.
For example:
class Drawable { virtual void render() = 0; }
class Rectangle : public Drawable { Rectangle(Point corner1, Point corner2); ... }
class Circle : public Drawable { Circle(Point center, float radius); ... }
turns into
data Point = Pt { x :: Float, y :: Float } deriving Show data Drawable = Rectangle Point Point | Circle Point Float
I agree that this does look more succinct... but what if I write some generic code for the in the render method of the Drawable class and package it into a library.. Now my client want to write another subclass for Drawable... He can do that in any other file... package.. whatever... How would he do that in Haskell ??? considering he may not modify the source file in while i have defined the Drawable ADT.. I know it is possible using Type Classes... Have a Drawable Type Class.. etc.. etc.. Is there probably a better way of dooing it ??
render :: Drawable -> IO () render (Rectangle p1 p2) = putStrLn (concat ["Rectangle from ", show p1, " to ", show p2, "."]) render (Circle center radius) = putStrLn (concat ["Circle at ", show center, " with radius ", show radius, "."])
This inverts the control from the OO structure; in the OO the interface is centralized and the data is spread throughout the source. In the pattern-matching style, the data is centralized (in the ADT) but the interface can be spread out.
For example, to add a new function "area()" to Drawable, in the OO style you have to add it to Drawable and put an implementation into every class that descends from Drawable, modifying all those modules. But in Haskell you could declare a new function in one place:
area :: Drawable -> Float area (Rectangle p1 p2) = abs (x p2 - x p1) * abs (y p2 - y p1) area (Circle _ r) = pi * r * r
On the other hand, adding new data to Rectangle or Circle requires changing all the pattern matches spread throughout the source, which is somewhat annoying. So there are benefits of both styles.
It's possible to emulate the OO style in Haskell, using existential types, but it is a lot harder. It's easier to stick with what the language is good at! :)
Hmmm... I suspect this answers the question I stated above...
-- ryan
-Arun

Hello Arun, Monday, October 13, 2008, 2:50:27 PM, you wrote:
I agree that this does look more succinct... but what if I write some generic code for the in the render method of the Drawable class and package it into a library..
i recommend you to read http://haskell.org/haskellwiki/OOP_vs_type_classes first and then look into http://haskell.org/haskellwiki/Library/Streams - it's a good example of extensible library written using type classes. later i've used this approach to write extensible library in C++ using templates (not classes) -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

(First of all, sorry for the double reply...)
2008/10/13 Arun Suresh
Now my client want to write another subclass for Drawable... He can do that in any other file... package.. whatever...
How would he do that in Haskell ??? considering he may not modify the source file in while i have defined the Drawable ADT..
I know it is possible using Type Classes... Have a Drawable Type Class.. etc.. etc.. Is there probably a better way of dooing it ??
That depends on what you want to do. If all you want to do is allow the client to pass Drawable's to your API functions, which then only use the class interface, you can get away without existentials:
class Drawable d where area :: d -> Int draw :: d -> IO ()
foo :: Drawable d -> IO () foo d = do putStrLn $ "This shape has area "++show (area d) draw d
On the other hand, if you want to do something like maintain a list of drawables then you'll need to use existential types (and therefore include {-# OPTIONS -fglasgow-exts #-} at the top of the source file):
data Painting = Painting [(forall d. Drawable d => d)]
addToPainting :: Drawable d => d -> Painting -> Painting addToPainting d (Painting ds) = Painting (d:ds)
emptyPainting :: Painting emptyPainting = Painting []
computeTotalArea :: Painting -> Int computeTotalArea (Painting []) = 0 computeTotalArea (Painting (d:ds)) = area d + computeTotalArea (Painting ds)
drawPainting :: Painting -> IO () drawPainting (Painting []) = return () drawPainting (Painting (d:ds)) = draw d >> drawPainting (Painting ds)
You can then expose just the Painting type as an abstract type (with no exposed constructor), and this is similar to making, say, Drawable *painting; Note that in all these examples (including the C++ one), you *only* get the class interface to work with. The main difference is that in C++, it's a bit easier to downcast, whereas in Haskell it's practically impossible, short of modifying your class interface:
class Drawable d where toCircle :: d -> Maybe Circle toCircle _ = Nothing -- default implementation, so clients needn't implement
instance Drawable Circle where toCircle c = Just c
This could be done more generally as well, if you have a class hierarchy,
class Drawable d => PointyShape d data AnyPointy = PointyShape d => AnyPointy d class Drawable d where toPointy :: d -> Maybe AnyPointy
and so on. But beware the difference between the two signatures Drawable a => a -> a -> ... (Drawable a,Drawable b) => a -> b -> ... as pointed out in the OOP vs type classes article. The former needs a guarantee that the two arguments are the SAME drawable, and once you're in an existential, you've lost that information (again, short of doing some hokey stuff with extra class methods, i.e. convert :: Drawable d' => d -> d' -> Maybe d but that's just really ugly and you probably don't want to do that...) Hope this helps, steve

Arun Suresh wrote:
Hello folks,
Im kinda new to haskell. Ive only been fiddling around with it for bout 3 - 4 weeks now. And for the life of me... i cant seem to figure out why this doesnt work :
class Foo a where fooFunc :: a -> Int
data FooData = FData
instance Foo FooData where fooFunc _ = 10
class Bar a where barFunc :: (Foo b) => a -> b -> Int
data BarData = BData
instance Bar BarData where barFunc _ FData = 20
Ooo, ooo, I know this one, it's... oh, wait, I've been at work all day, so by now 30 other people have already replied. Heh. I need to find another day job... ;-)
participants (5)
-
Andrew Coppin
-
Arun Suresh
-
Bulat Ziganshin
-
Ryan Ingram
-
Stephen Hicks