Fri, 10 Dec 1999 00:08:08 +0100, Girard Milmeister <[EMAIL PROTECTED]> pisze:
> A standard example in OO is a container of objects (values) of
> type FIGURE. It can hold also objects of subclass of FIGURE, like
> Polygon and Circle. Iterating over the container one can call e.g.
> obj.draw() an operation common to all figures. A central idea is
> of course that of extensibilty, i.e. defining new subclasses of
> FIGURE without changing any of the code handling the container.
>
> How would one implement something like this in a pure, lazy
> functional style (in Haskell)?
Often it's sufficient to represent a figure by a record of methods,
represented by functions.
Those functions need not to have a "this" parameter (which would have
to have different type for various figures), because each instance
can have different functions (unlike C++, where the method behavior
depends on the class only) and in functional languages functions can
refer to values known only at their creation (unlike function pointers
in C, C++, and Pascal). So methods have completely known types.
data Figure = Figure{
draw :: (Int,Int) -> IO (),
boundingBox :: (Int,Int,Int,Int),
contains :: (Int,Int) -> Bool,
move :: (Int,Int) -> Figure,
name :: String,
getColor :: Color,
setColor :: Color -> Figure}
It's generally hard to make functions working on several objects, e.g.
isContainedIn :: Figure -> Figure -> Bool -- (not a method).
I've recently experimented with dialog windows in text mode. We want
various widgets to return different types, e.g. a list of checkboxes
should yield [Bool]. But the dialog displaying engine needs to have
a list of widgets, to be able to maintain the focus and send keys to
appropriate widgets. How to do it?
A solution (it uses IORefs, a GHC and Hugs extension): Let's assume
that a widget is parametrized by the type it yields, and that a couple
of composed widgets (e.g. put together vertically) is also a widget,
with a type somehow combining types of its components. A dialog
consists of one complex widget. To maintain the focus, let's split
a widget into the part possibly depending on the type of the widget,
but not depending on how it is composed, and the part having constant
type, with explicitly mentioned components:
data Widget a = Widget{
size :: (Int,Int){-size-},
drawFirst :: (Int,Int){-pos-} -> IO (),
actions :: [WidgetAction],
getValue :: IO a}
data WidgetAction = WidgetAction{
draw :: (Int,Int){-pos-} -> Bool{-has focus?-} -> IO (),
keyPressed :: Key -> (Int,Int){-pos-} -> IO Bool{-close dialog?-}}
It works! No need for heterogenous list of widgets of varying types.
It is possible to write functions that combine widgets and
runDialog :: Widget a -> (Int,Int){-pos-} -> IO a
(IORefs may be used to make more imperative feel of the above solution
for figures. setColor could have type Color -> IO () instead of
returning a new Figure, and getColor would be IO Color then. I won't
try to claim now which is better. It probably depends.)
There is an extension among some Haskell compilers, including GHC,
called existentially quantified types. I think that other people
would advise it first, even in cases it's not really needed :-)
It's generally expected to be in Haskell2 and is really cool. It's
described in the GHC manual and was discussed a bit at the beginning
of November on [EMAIL PROTECTED] mailing list. It allows writing
types like this:
class Figure f where
draw :: f -> (Int,Int) -> IO ()
...
data AnyFigure = forall f. Figure f => AnyFigure f
-- (f -> (Int,Int) -> IO ()) -- you can also place methods here
In this case using an existential type gives us close to nothing: a
Figure can be converted to a tuple of methods (with completely known
types) without loss of capabilities. You can express that moving a
figure does not change its type, but I don't know if it's useful.
There are situations where existentials are unavoidable, or when
they increase performance much by enabling sharing and persistency
of computed values.
--
__("< Marcin Kowalczyk * [EMAIL PROTECTED] http://qrczak.ids.net.pl/
\__/ GCS/M d- s+:-- a22 C+++>+++$ 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-