--- Robert Will <[EMAIL PROTECTED]> wrote: -- > Here -- > is a quesion for the -- > most creative of thinkers: which is the design (in -- > proper Haskell or a -- > wide-spread extension) possibly include much -- > intermediate type classes and -- > other stuff, that comes nearest to my desire?
Hello, I've often wondered the same thing. I've found that one can simulate several OO paradigms. Note that these aren't particularly elegant or simple. ---- Using Data Constructors: ---- > data Shape = Rectangle {topLeft :: (Int, Int), bottomRight :: (Int,Int) } > | Circle {center :: (Int,Int), radius :: Int } This allows you have a list of shapes > shapeList :: [Shape] > shapeList = [ Rectangle (-3,3) (0,0), Circle (0,0) 3 ] When you want member functions, you need to specialize the function for all the constructors. > height :: Shape -> Int > height (Rectangle (a,b) (c,d)) = b - d > height (Circle _ radius) = 2 * radius Disadvantages: 1) When a new Shape is needed, one needs to edit the original Shape source file. 2) If a member function is not implemented for a shape subclass, it will lead to a run-time error (instead of compile-time). Advantages: 1) Simple Syntax 2) Allows lists of Shapes 3) Haskell98 Example: GHC's exception types http://www.haskell.org/ghc/docs/latest/html/base/Control.Exception.html ---- Using Classes ---- Classes can be used to force a type have specific functions to act upon it. >From our previous example: > class Shape a where > height :: a -> Int > > data Rectangle = Rectangle {topLeft :: (Int, Int), bottomRight :: (Int,Int) } > data Circle = Circle {center :: (Int,Int), radius :: Int } > > instance Shape Circle where > height (Circle _ radius) = 2 * radius > > instance Shape Rectangle where > height (Rectangle (a,b) (c,d)) = b - d In this case, something is a shape if it specifically has the member functions associated with Shapes (height in this case). Advantages 1) Simple Syntax 2) Haskell98 3) Allows a user to easily add Shapes without modifying the original source. 4) If a member function is not implemented for a shape subclass, it will lead to a compile-time error. Disadvantages: 1) Lists of Shapes not allowed Example: Haskell 98's Num class. http://www.haskell.org/ghc/ ---- Classes with Instance holder. ---- There have been a few proposals of ways to get around the List of Shapes problem with classes. The Haskell98 ways looks like this > data ShapeInstance = ShapeInstance { ci_height :: Int } > toShapeInstance :: (Shape a) => a -> ShapeInstance > toShapeInstance a = ShapeInstance { ci_height = (height a) } > instance Shape ShapeInstance where > height (ShapeInstance ci_height) = ci_height So when we want a list of shapes, we can do > shapeList = [ toShapeInstance (Circle (3,3) 3), > toShapeInstance (Rectangle (-3,3) (0,0) ) ] Of course this also has it's disadvantages. Everytime a new memeber function is added, it must be noted in the ShapeInstance declaration, the toShapeInstance function, and the "instance Shape ShapeInstance" declaration. Using a haskell extention, we can get a little better. Existentially quantified data constructors gives us this: > data ShapeInstance = forall a. Shape a => ShapeInstance a > > instance Shape ShapeInstance where > height (ShapeInstance a) = height a > > shapeList = [ ShapeInstance (Circle (3,3) 3), > ShapeInstance (Rectangle (-3,3) (0,0) ) ] The benefits of this method are shorter code, and no need to update the ShapeInstance declaration every time a new member function is added. ---- Records extention ---- A different kind of inheritance can be implemented with enhanced haskell records. See http://research.microsoft.com/~simonpj/Haskell/records.html and http://citeseer.nj.nec.com/gaster96polymorphic.html for in depth explinations. I'm not sure if these have been impemented or not, but it would work as follows. The inheritance provided by the above extentions is more of a data inheritance than a functional inheritance. Lets say all shapes must have a color parameter: > type Shape = {color :: (Int,Int,Int)} > type Circle = Shape + { center :: (Int,Int), radius :: (Int) } > type Rectangle = Shape + { topLeft :: (Int,Int), bottomRight :: (Int, Int) } So now we can reference this color for any shape by calling .color. > getColor :: (a <: Shape ) -> a -> (Int,Int,Int) > getColor a = a.color I'm not sure how the records extention could be used with Classes with instance holders to provide an even more plentiful OO environment. So I'll conclude this email with the observation that Haskell supports some OO constructs although not with the most elegance. _______________________________________________ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell