Re: List of class instances?

1999-08-19 Thread Fergus Henderson

On 18-Aug-1999, Michael Hobbs <[EMAIL PROTECTED]> wrote:
> What I would like to do is have a function that takes a list of
> "objects", where the objects are all instances of a particular class,
> but not necessarily the same type. Example:
> 
> class Shape a where
>   extent :: a -> Point
>   ...
> biggest :: Shape a => [a] -> Point
> biggest listOfShapes = ...
> 
> The closest I could come to achieving this in standard Haskell is:
> 
> data Shape = Shape {extent :: Point, ...}
> class ShapeClass a where
>   mkShape :: a -> Shape
> biggest :: [Shape] -> Point
> biggest listOfShapes = ...
> 
> The problem with this is that the caller of `biggest' needs to call
> `mkShape' on each element in the list before it can construct the list.
> Not _bad_, but rather unwieldy. The caller can't simply use `map' either
> if each element is of a different type.
> 
> Anyone know of an elegant way to do this?

I think that's the best you can do in standard Haskell.

> I'd prefer to stay away from
> compiler-specific features, but if something like existential types is
> just what I need, I guess I can bite the bullet.

Existential types are indeed designed for exactly this kind of circumstance.
However, existential types do not remove the need to call a function such as
`mkShape' to convert every element of the list into a single common type.
They just allow you to avoid converting your type-class `Shape' into a record.

Here's what it would look like with existential types.

-- class Shape is unchanged from your original example
class Shape a where
  extent :: a -> Point
  ...

-- here we define an existential type that can hold any type of shape
data AnyShape = Shape a => mkAnyShape a

-- here we make the type AnyShape an instance of the class Shape,
-- by just unwrapping the `mkAnyShape' constructor and forwarding
-- the method calls
instance Shape AnyShape where
extent (mkAnyShape a) = extent a
...

-- the code for biggest is unchanged from your original example
biggest :: [AnyShape] -> Point
biggest listOfShapes = ...

If you want you can delete all the occurrences of `Any' above,
overloading `Shape' as both a type name and a class name.

Note that the `data' and `instance' definitions in this example are
boiler-plate code.  I've previously suggested here that for single-parameter
type classes the compiler could generate such definitions automatically.
However, this suggestion did not meet with universal acceptance;
none of the current implementations of existential type classes
do anything along those lines.

-- 
Fergus Henderson <[EMAIL PROTECTED]>  |  "I have always known that the pursuit
WWW:   |  of excellence is a lethal habit"
PGP: finger [EMAIL PROTECTED]| -- the last words of T. S. Garp.





Re: List of class instances?

1999-08-19 Thread Marcin 'Qrczak' Kowalczyk

Thu, 19 Aug 1999 19:08:49 +1000, Fergus Henderson <[EMAIL PROTECTED]> pisze:

> > The problem with this is that the caller of `biggest' needs to call
> > `mkShape' on each element in the list before it can construct the list.
> > Not _bad_, but rather unwieldy. The caller can't simply use `map' either
> > if each element is of a different type.
> > 
> > Anyone know of an elegant way to do this?
> 
> I think that's the best you can do in standard Haskell.

One could define a specific polymorphic operator instead of : or [,,,]
to create such lists, so it would remove explicit `mkShape' calls.

-- 
 __("+++$ UL++>$ P+++ L++>$ E-
  ^^W++ N+++ o? K? w(---) O? M- V? PS-- PE++ Y? PGP->+ t
QRCZAK  5? X- R tv-- b+>++ DI D- G+ e> h! r--%>++ y-






List of class instances?

1999-08-18 Thread Michael Hobbs

What I would like to do is have a function that takes a list of
"objects", where the objects are all instances of a particular class,
but not necessarily the same type. Example:

class Shape a where
  extent :: a -> Point
  ...
biggest :: Shape a => [a] -> Point
biggest listOfShapes = ...

The closest I could come to achieving this in standard Haskell is:

data Shape = Shape {extent :: Point, ...}
class ShapeClass a where
  mkShape :: a -> Shape
biggest :: [Shape] -> Point
biggest listOfShapes = ...

The problem with this is that the caller of `biggest' needs to call
`mkShape' on each element in the list before it can construct the list.
Not _bad_, but rather unwieldy. The caller can't simply use `map' either
if each element is of a different type.

Anyone know of an elegant way to do this? I'd prefer to stay away from
compiler-specific features, but if something like existential types is
just what I need, I guess I can bite the bullet.

Thanks,
- Michael Hobbs