Interesting problem not difficult to solve in OCaml. For sure, you could use the object system but I do not like it a lot, and it’s not really fun. To have more fun, and since it’s an expression problem, lets use the full expressiveness power of the OCaml type system : modules, first-class modules and GADT.
First define your algebra on shapes as a module type:
module type SHAPE = sig
type t
val area : t -> float
val draw : t -> unit
end
then implement your different kinds of shapes:
module Point : SHAPE = struct
type t = {x : int; y : int}
let area _ = 0.0
let draw {x; y} = ...
end
module Circle : SHAPE = struct ... end
module Rectangle : SHAPE = struct ... end
Now, since you want containers for shapes (to iterate over them), you need to define the type of shapes, and that’s where we use GADT. According to your definition, a shape is something with an area that we can draw. Here’s how we define this in OCaml:
type shape = Shape : (module SHAPE with type t = 'a) * 'a -> shape
and now you can define, for instance, a list of shape:
let l = [Shape ((module Point), p1); Shape ((module Circle), c1); ...]
(* and iterate over it *)
List.iter (fun (Shape ((module M), v)) -> M.draw v) l
Basically a shape
(as defined with a GADT) is similar to an object, for instance with a point:
let point x y = object
val x = x
val y = y
method area = 0.0
method draw () = ()
end
but here the instance variable (x
and y
) are really what define a point, and this type cannot be projected out of this object in the type system (that’s one of the reason I don’t like a lot the object sytem). And this object is just a flatten representation of the shape
type
For a more detail use of this method see this thread.