Contributed by Chris Rathman (based on help from Andreas Rossberg)
See also: Alice ML - Using Records
exception Abstract
signature SHAPE =
sig
val getX : unit -> int
val getY : unit -> int
val setX : int -> unit
val setY : int -> unit
val moveTo : int * int -> unit
val rMoveTo : int * int -> unit
val draw : unit -> unit
end
functor Shape (val x:int val y:int) :> SHAPE =
struct
val x = ref x
val y = ref y
fun getX () = !x
fun getY () = !y
fun setX x' = x := x'
fun setY y' = y := y'
fun moveTo (x', y') = ( setX x'; setY y' )
fun rMoveTo (dx, dy) = moveTo(!x + dx, !y + dy)
fun draw () = raise Abstract
end
signature RECTANGLE =
sig
include SHAPE
val getWidth : unit -> int
val getHeight : unit -> int
val setWidth : int -> unit
val setHeight : int -> unit
end
functor Rectangle (val x:int val y:int val width:int val height:int) :> RECTANGLE =
struct
structure Shape = Shape (val x=x val y=y)
open Shape
val width = ref width
val height = ref height
fun getWidth () = !width
fun getHeight () = !height
fun setWidth width' = width := width'
fun setHeight height' = height := height'
fun draw () = print(
"Drawing a Rectangle at:(" ^ Int.toString(getX()) ^ "," ^ Int.toString(getY()) ^
"), Width " ^ Int.toString(getWidth()) ^ ", Height " ^ Int.toString(getHeight()) ^ "\n")
end
signature CIRCLE =
sig
include SHAPE
val getRadius : unit -> int
val setRadius : int -> unit
end
functor Circle (val x:int val y:int val radius:int) :> CIRCLE =
struct
structure Shape = Shape (val x=x val y=y)
open Shape
val radius = ref radius
fun getRadius () = !radius
fun setRadius radius' = radius := radius'
fun draw () = print(
"Drawing a Circle at:(" ^ Int.toString(getX()) ^ "," ^ Int.toString(getY()) ^
"), Radius " ^ Int.toString(getRadius()) ^ "\n")
end
fun drawLoop pShape =
let
structure S = unpack pShape : SHAPE
in
S.draw();
S.rMoveTo(100, 100);
S.draw()
end
fun polymorph () =
let
(* create some shape instances *)
val scribble = [pack (Rectangle(val x=10 val y=20 val width=5 val height=6)) : RECTANGLE,
pack (Circle(val x=15 val y=25 val radius=8)) : CIRCLE]
structure Rect = Rectangle(val x=0 val y=0 val width=15 val height=15)
(* example downcast *)
structure R = unpack (hd scribble) : RECTANGLE
structure C = unpack (hd (tl scribble)) : CIRCLE
in
(* iterate through the list and handle shapes polymorphically *)
List.map drawLoop scribble;
(* call a rectangle specific function *)
Rect.setWidth(30);
Rect.draw()
end;
polymorph();
|
Drawing a Rectangle at:(10,20), Width 5, Height 6 Drawing a Rectangle at:(110,120), Width 5, Height 6 Drawing a Circle at:(15,25), Radius 8 Drawing a Circle at:(115,125), Radius 8 Drawing a Rectangle at:(0,0), Width 30, Height 15 |