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
next prev 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