The shape design problem

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. :slight_smile:

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.

12 Likes