Version française
Home     About     Download     Resources     Contact us    
Browse thread
generic functions
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Brian Hurt <bhurt@s...>
Subject: Re: [Caml-list] generic functions
On Sun, 9 Jan 2005 wiedergaenger@fastmail.fm wrote:

> I just got from LISP to OCaml, and wondered if there is an equivalent of
> generic functions from LISP (CLOS) in OCaml. In the Common Lisp Object
> System methods don't belong to certain objects/classes. They are just
> function specializing on the argument types. So basically I want to
> write something like:
> 
> let foo (x : int) = x*x;;
> let foo (x : float) = x*.x;;
> 
> This, obviously, will not work since foo is just redefined by the second
> statement. One would think, that having methods not being belonging to
> objects/classes, is rather pointless. Well 95% of the time, there is no
> necessity for that. But in the other 5%, it is really helpful. 
> 

The short answer is no.  For two reasons- first, Ocaml doesn't keep type 
information (in most cases) of data at run time, the type information is 
used during compilation and then tossed.  Which means that Ocaml doesn't 
have a way at run time to tell which version of the function to call.  And 
second, and more importantly, overloading (like you're doing above) would 
make type inference extremely difficult if not impossible.

There are several ways to "work around" this limitation in Ocaml, 
depending upon what exactly you are doing.

1) Just use different functions.  Do:
	let ifoo x = x * x;;
	let ffoo x = x *. x;;
and just call the correct one.  This is generally not as bad a solution as 
you might think.

2) Use variant types:
	type number = Int of int | Float of float;;
	let foo = function
		| Int(x) -> Int(x*x)
		| Float(x) -> Float(x*.x)
	;;
The tags in this case are the type information Ocaml would normally "throw 
away".

3) Use modules:
	module type Mult = sig
		type t
		val mul : t -> t -> t
	end
	module type Foo = sig
		type t
		val foo : t -> t
	end
	module Make(M: Mult) : Foo with type t = M.t = struct
		type t = M.t
		let foo x = M.mul x x
	end;;
	module IMult = struct
		type t = int
		let mul x y = x * y
	end;;
	module IFoo = Make(IMult);;
	module FMult = struct
		type t = float
		let mul x y = x *. y
	end
	module FFoo = Make(FMult);

For this simple example, modules and functors are clunky- but they allow 
the user of your code to create new foo functions, which is usefull.

With the exception of certain artificial contests (Paul Graham) I've never 
met a real world problem that needed overloading, or even benefitted 
signifigantly from overloading that didn't benefit just as much or more 
from one of the solutions above.

Brian