Version française
Home     About     Download     Resources     Contact us    
Browse thread
stl?
[ 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] stl?


On Wed, 4 Mar 2009, Jon Harrop wrote:

> On Wednesday 04 March 2009 00:11:32 you wrote:
>> On Tue, 3 Mar 2009, Jon Harrop wrote:
>>> Functors give you the same capability in OCaml but they are rarely used
>>> precisely because the functionality is not very useful.
>
> Also largely because there is not enough good tutorial information available
> explaining how to leverage functors.

This is another large factor.  The three reasons functors aren't used very 
much are because:
1) They're a big, scary name,
2) They're slightly less efficient,
3) There are no good tutorials about how to use them, and
4) A fanatical devotion to the pope.

I'll come in again...

> Efficiency is only important in the context of functors when abstracting very
> fast and common functions like arithmetic without defunctorizing your code. I
> don't think that is why people avoid functors in OCaml.

Arithmetic operators that are themselves very cheap.  The cost of 
functorization is large compared to, say, floating point addition- but 
small compared to the cost of, say, vector addition.  And it's expensive 
only because Ocaml lacks an obvious optimization (defunctorization).  And 
yet this whole discussion is simply proving my point- we're comparing 
clock cycles here.  Yes, if you're writing the inner loops of a numeric 
computation that'll take days to run, maybe, *MAYBE*, the cost difference 
of calling via a functor is worthwhile to worry about.  But that's the 
point where I start being really tempted to drop down to C, or even 
assembly (for SSE Vectorization).  But for the vast bulk of people 
programming, performance (at least on the clock cycle level) simply isn't 
that important- as demonstrated by all the "real work" being done in 
hideously slow languages like Ruby, Python, etc...

> I think that is a reflection of what the communities desire rather than what
> they already have. OCaml is already fast (particularly on amd64) but OCamlers
> always want even better performance. Haskell's development experience is a
> real sore point and they want to address that. However, I would also say that
> both communities are moving very slowly toward these goals.

Both languages have their annoyances.  Adjusting for the fact that I'm 
significantly more familiar with and comfortable with Ocaml, I don't find 
Haskell that much more difficult to work in.

>
>> The type classes comparison isn't even an analogy- it's a precise
>> relationship. Anywhere you might be thinking, in Ocaml, "this would be a
>> nice place to use a type class", use a functor.  You want operator
>> overloading in Ocaml?  You got it: use a functor.
>
> Functors do not facilitate operator overloading. You still end up with a
> combinatorial explosion in the number of operator names.

Bwuh?

Try this.  Let's reimplement Haskell's Fractional class, in Ocaml, and 
then do Newton's method using this new Fractional class.  Then I'll 
provide implementations that use both floats and ratios (arbitrary 
precision fractions).  First, we need to define Fractional.  That's just:

module type Fractional = sig
 	type t
 	val ( +. ) : t -> t -> t
 	val ( -. ) : t -> t -> t
 	val ( *. ) : t -> t -> t
 	val ( /. ) : t -> t -> t
 	val fabs : t -> t
 	(* other functions elided from brevity *)
end;;

Now we write our functorized Newton's method:

module Make(F: Fractional) = struct

 	open F;;

 	let rec newtons epsilon f df x =
 		let x' = x -. ((f x) /. (df x)) in
 		if (fabs (x -. x')) < epsilon then
 			x'
 		else
 			newtons epsilon f df x'
 	;;

end;;

Now we provide an instance of Fractional for floats:

module FloatFractional = struct
 	type t = float
 	let ( +. ) = ( +. );;
 	let ( -. ) = ( -. );;
 	let ( *. ) = ( *. );;
 	let ( /. ) = ( /. );;
 	let fabs x = abs_float x;;
end;;

module FloatNewtons = Make(FloatFractional);;

Now we provide an instance for Ratios:

module RatioFractional = struct
 	type t = Ratio.ratio;;
 	let ( +. ) = Ratio.add_ratio;;
 	let ( -. ) = Ratio.sub_ratio;;
 	let ( *. ) = Ratio.mult_ratio;;
 	let ( /. ) = Ratio.div_ratio;;
 	let fabs = Ratio.abs_ratio;;
end;;

module RatioNewtons = Make(RatioFractional);;

Viola.  Operator overloading.  In Ocaml.  And it's not that much worse 
than Haskell equivalent, once you realize that the definitions of 
Fractional, FloatFractional, and RatioFractional all should be in the 
standard library (and the latter two should be just called Float and 
Ratio).

And typeclasses have their problems as well- which are off topic for this 
list.

>
>> If this causes you a
>> knee jerk reaction about performance, ask yourself this: do you know how
>> type classes are implemented in Haskell, and what their performance hit
>> there is?  Now, imagine programming haskell where typeclasses are only
>> used in a very places- Ord, Eq, Monad.  No Num.  No Monoid.  No Show.
>> That's Ocaml.  Not that it has to be.
>
> I don't follow your breakdown. OCaml does not have Ord and Eq, it only has a
> hack for structural equality. Same for Show. Few people care about Monad, Num
> and Monoid.

The turn you missed was that I'm say "what if Haskell programmers used 
type classes as rarely as Ocaml programmers use functors?"  Typeclasses 
are a huge win in Haskell, but primarily because they get *used*.

>
> However, that is trivial to fix with run-time type information that can convey
> per-type functions. Both F# and my HLVM already do that.

I suppose we could sit around and whine that Ocaml doesn't have type 
classes, or reflection, or some other neat feature, that if it only had 
it, we could all these neat things with them.

Or we could use the equivalently powerfull features Ocaml *already* has...

Brian