caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Brian Hurt <bhurt@spnz.org>
To: Stephen Brackin <stephen.brackin@verizon.net>
Cc: caml-list@yquem.inria.fr
Subject: Re: [Caml-list] Duplicate functionality?
Date: Sat, 22 Oct 2005 16:12:34 -0500 (CDT)	[thread overview]
Message-ID: <Pine.LNX.4.63.0510220923370.9226@localhost.localdomain> (raw)
In-Reply-To: <0IOQ006I7LO24OK2@vms044.mailsrvcs.net>



On Fri, 21 Oct 2005, Stephen Brackin wrote:

> My biggest initial question is why OCaml has both a modules system and
> objects: Aren't they different ways of accomplishing the same things?

No.  And this is one of the most misunderstood things about Ocaml modules- 
that they are NOT just a weird and broken implementation of objects.  A 
better point of reference would probably be C++ templates (although Ocaml 
modules fix the complaints I have with C++ templates).

Modules are used for code that is "based on" other code.  An example makes 
this clearer.  Let's consider Newton's method for root find.  This is an 
incredibly powerfull algorithm that can be applied to a huge number of 
different number systems.  For example, it works on reals, it works on 
complexs, it works on quaterions, it works on integers, and it works on 
systems of non-linear equations (vectors and matricies).  And when I say 
it works on reals, I mean it works on all representations of reals- it 
works on IEEE floating point, it works on arbitrary precision rationals, 
it works on arbitrary precision floats, it works on fixed precision 
floats, etc.

All we need to implement Newton's method is a small set of basic 
operations.  We need subtraction, we need to be able to solve Ax = b given 
A and b (which is just x = b/A in most number systems, but we express it 
this way as it's more "natural" if A is the Jacobian matrix of partial 
derivitives and b is the vector residual), and we need some way to say 
we're "close enough" to the solution that we can stop.

With modules, we might write:

module type Req = sig
     type t (* the basic type of the number system *)
     type dt (* the type of derivitives- generally, this will be the same
              * as t, but in the case of vectors/matricies, t is a vector
              * while dt is a matrix.
              *)
     type et (* The type of the error value.  Often times this will be
              * the same as t above, but for "constructed" types
              * like complexes and vectors, type et will be whatever
              * real type they are made out of.
              *)
     val sub : t -> t -> t (* subtraction *)
     val solve : et -> dt -> t -> t (* Solve Ax = b to within epsilon.
                                     * Generally epsilon will be ignored,
                                     * and the solution will just be
                                     * x = b/A.
                                     *)
     val default_epsilon : et
     val within_epsilon : et -> t -> t -> bool
         (* Returns true if the two value differ by a factor of less
          * than epsilon.
          *)
end;;

module Make(Alg: Req) = struct

     exception Max_iters_reached of Alg.t

     let meth ?(epsilon = Alg.default_epsilon) ?(max_iters = max_int)
         f df x
     =
         (* Find a root to f given f and it's derivitive df starting
          * at an initial guess of x.
          *)
         let rec loop i x =
             if i > max_iters then
                 raise (Max_iters_reached x)
             else
                 let x' = Alg.sub x (Alg.solve epsilon (df x) (f x)) in
                 if Alg.within_epsilon epsilon x x' then
                     x'
                 else
                     loop (i+1) x'
         in
         loop 0 x
end;;

Now, we could probably implement something like this in objects- Newtons 
would be a base class calling out to virtual functions like solve and sub 
which would be implemented in concrete subclasses.  But there are several 
large advantages to using modules in this case.

The first one is types.  Note that were I to implement Newtons with 
floating point numbers, like:

module Float = struct
     type t = float
     type dt = float
     type et = float
     let sub = ( -. )
     let solve (_: et) a b = b /. a
 	let default_epsilon = 1.e-14;;
 	let within_epsilon e x y =
         ((abs_float ((x -. y) /. x)) < e) || ((abs_float (x -. y)) < e)
end;;

module FloatNewtons = Make(Float);;

Ocaml figures out the t, dt, and et are "all the same type", and I have a 
function with the right signature.  This is doable with dynamic type 
checking and objects, but not static.  Or at least I've never seen it done 
in a static language.

Another advantage of modules over structures in the type arena is to be 
able to express the "these two objects need to be of the same 
implementation" as a type constraint.  An example of this is the compare 
function in Map or Set.  The compare function wants to gaurentee that the 
two maps or sets you are comparing have the same ordering.  They can do 
that using modules and functors.

Another advantage of modules and functors is, with ocamldefun, the ability 
to remove the layer of vituralization, and actually have myself a 
high-performance Newton's method implementation.

Another advantage is that it allows objects to be objects, and stop having 
to be things they're not, like name spaces.  Ocaml objects have a hard 
time implementing the Singleton pattern, for example.  Of course they do- 
you should be using modules for that.

Brian


  parent reply	other threads:[~2005-10-22 21:10 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-10-22  1:04 Stephen Brackin
2005-10-22  3:31 ` [Caml-list] " Jon Harrop
2005-10-22  5:57   ` Matt Gushee
2005-10-22  8:47   ` Gerd Stolpmann
2005-10-22  5:49 ` Jacques Garrigue
2005-10-22 10:07   ` Lauri Alanko
2005-10-22 21:12 ` Brian Hurt [this message]
2005-10-24  3:14 ` Ant: " Martin Chabr
2005-10-25 16:25   ` Didier Remy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Pine.LNX.4.63.0510220923370.9226@localhost.localdomain \
    --to=bhurt@spnz.org \
    --cc=caml-list@yquem.inria.fr \
    --cc=stephen.brackin@verizon.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).