I've been learning OCaml because I had a project that needed high
performance and OCaml tends to do quite well in that regard. For now
OCaml still has the performance edge, though Haskell seems to be
steadily closing the gap.
I also tend to think that if you're new to functional programming (as
I am) it can be nice to be able to fall back on imperative programming
where needed - this is just a pragmatic consideration on my part. I
also tend to like the ability to to OO (the 'O' in OCaml) as that's a
familiar paradigm.
Haskell does seem to be getting more mindshare now, but from what I've
heard there are probably more paid OCaml (and *ML ) programmers than
there are paid Haskell programmers - could be changing, though. OCaml
tends to get a lot of use in the financial trading (quants) space -
for example Janes St. Capital, a London trading firm employs a lot of
OCaml programmers. They recently started an OCaml blog:
http://ocaml.janestcapital.com/ Some good posts there already.
Phil
If concurrency is a requirement then perhaps JoCaml should also be
investigated. Mauricio Fernandez did some comparisons and shares his
conclusions on his eigenclass blog:
http://eigenclass.org/hiki/wide-finder-conclusions
Some quotes:
" * we cannot dismiss constant factors. JoCaml code written by an
individual in an afternoon can perform better than Erlang code refined
over the course of one month by Erlang experts*2 on a per-core basis,
while scaling just as well.
* JoCaml allows to express and reason about concurrent and
distributed systems at very high level, leaving little place for the
sort of bugs that infest code written with threads and shared state.
(I have written a couple fault-tolerant systems in JoCaml that would
have been much harder with threads.)
* Erlang's major strength is fault-tolerance, scalability, etc.,
not raw performance; promoting Erlang by saying that it will be
"faster given enough cores" is disingenuous because it conceals the
existence of alternatives like JoCaml that can scale just as well but
perform much better per core. "
I haven't tried JoCaml yet, but it sounds like it's worth a look.
Maybe it would be a good topic for a pdxfunc presentation?
Phil
You haven't said what it is you're trying to write.
If you think you may need infinite data structures, Haskell is a win.
If you want speed of compiled code, OCaml is a win.
Haskell has a more expressive type system, so some things are easier
to write in it than in OCaml. For example, "deriving (Show)" makes life
much easier when you want to print out data.
I've used both languages a fair amount, and both are pleasant to program in.
-- Paul
I don't think the parser has anything to do with it, but it is easy to
write leaky programs in Haskell. If you are processing huge amounts of
data you can really get yourself in trouble.
Fortunately, these kind of problems are easy to detect and (when
profiling early and often) not too hard to track down. Laziness can
make your program very space effecient as data doesn't have to be
loaded until it's needed. Assuming your are processing your data
row-at-a-time (or line-at-a-time), it's very possible to write a
program that uses very little memory. If you are loading data from a
database, Takusen is a well-supported library that supports lazy
queries. If data is coming from the filesystem, GHC's file I/O is lazy
by default.
On the issue of parallelism, GHC has a very nice set of parallel
primitives. Note these are not *concurrency* primitives, in the sense
of remote processes working together, but parallelizing your code to
run on multiple cores on the same machine. There isn't a lot written
on how to use them but they do work.
>
> I don't really know much about either language. I've heard that
> Haskell is a "pure" functional language, where Ocaml's enhancements of
> the past decade or so have added side effects. But, besides a
> dogmatic belief in "one right way", are there real dangers for writing
> in a less pure form? Are there practical tradeoffs I should consider?
One measurable advantage of purity is confidence in the behavior of
your code. If a function has side effects, they show up in the type
and you can't hide from it. Purity gives you isolation of effects and
really helps isolate bugs. You can narrow in on one function without
worrying about global side effects (unless, of course, that function
uses side-effects).
Search the internet for the paper "Wearing the hair shirt" - it's a
great discussion of the advantages of a pure, lazy functional
language.
>
> What about libraries of code. Haskell certainly has more people's
> attention. I've browsed around, and there seem to be quite a few
> libraries available in Haskell, compared to Ocaml.
http://hackage.haskell.org/packages/archive/pkg-list.html is a good
place to start looking.
>
> Anyway, I would greatly appreciate any insight you can add to my
> questions.
One caveat is that learning Haskell is definitely a character-building
exercise (in the sense your parents used to tell you). I came from an
OO background with no functional programming experience. The learning
curve was very steep. However, I feel I am a much better programmer
for it and am glad to have done it.
Justin
>
> On the issue of parallelism, GHC has a very nice set of parallel
> primitives. Note these are not *concurrency* primitives, in the sense
> of remote processes working together, but parallelizing your code to
> run on multiple cores on the same machine.
I've heard rumors to this effect...
> There isn't a lot written
> on how to use them but they do work.
>
Have you used these features and if so would you be interested in
doing a presentation on them?
>
> One caveat is that learning Haskell is definitely a character-building
> exercise (in the sense your parents used to tell you). I came from an
> OO background with no functional programming experience. The learning
> curve was very steep.
This is part of what led me to learn OCaml first (still learning it).
I'm hoping that Haskell will be a bit less daunting after I've done
some OCaml ;-)
Oh, the other thing that tipped the scales in favor of learning OCaml
first for me was the rocaml bridge between Ruby and OCaml - I don't
know if thats a consideration for the original poster or not. Could
be nice if you're using Rails for your Web programming and you want
OCaml for backend, highspeed processing.
Phil
I wish I had used them enough to say something useful, but I don't
think I have. Don Stewart wrote a great blog post about them a bit
ago:
http://cgi.cse.unsw.edu.au/~dons/blog/2007/11/29#smoking-4core
http://www.cse.unsw.edu.au/~dons/blog/2007/11/29#smoking
Justin
>
>
> If concurrency is a requirement then perhaps JoCaml should also be
> investigated. Mauricio Fernandez did some comparisons and shares his
> conclusions on his eigenclass blog:
> http://eigenclass.org/hiki/wide-finder-conclusions
>
> Some quotes:
>
> " * we cannot dismiss constant factors. JoCaml code written by an
> individual in an afternoon can perform better than Erlang code refined
> over the course of one month by Erlang experts*2 on a per-core basis,
> while scaling just as well.
>
> * Erlang's major strength is fault-tolerance, scalability, etc.,
> not raw performance; promoting Erlang by saying that it will be
> "faster given enough cores" is disingenuous because it conceals the
> existence of alternatives like JoCaml that can scale just as well but
> perform much better per core. "
It should probably be pointed out that Wide Finder is just one
benchmark, which happens to emphasize some areas which Erlang is
notorious weak on (i.e. not designed with them in mind). It's also a
short-running data processing task. If the task were running a
complex system for a year with no downtime, the "constant factors"
would likely run the other way. A program written in an afternoon in
Erlang using OTP will likely satisfy this requirement better than what
two JoCaml experts can produce in a month.
(Also, for the record, the current wide finder front runner is.... Perl)
-kevin
>
>
>>
>> One caveat is that learning Haskell is definitely a character-
>> building
>> exercise (in the sense your parents used to tell you). I came from an
>> OO background with no functional programming experience. The learning
>> curve was very steep.
>
> This is part of what led me to learn OCaml first (still learning it).
> I'm hoping that Haskell will be a bit less daunting after I've done
> some OCaml ;-)
I learned OCaml a while before learning Haskell, and I suspect it will
still be rather daunting. But also rewarding!
-kevin
Just curious, is there an equivilent to camlp4 in the Haskell world?
Some way of manipulating the AST?
Phil
Yes, Template Haskell.
Of course, you're better using Lisp or Scheme for this kind of thing. :-)
-- Paul
True.
Let me show an example (in OCaml, but it probably maps to Haskell
pretty well) where metaprogramming seems like it would be a win. I
was going through the OCaml tutorial a while back and decided to
expand their expr type to include a numeric value:
type expr = Plus of expr * expr (* means a + b *)
| Minus of expr * expr (* means a - b *)
| Times of expr * expr (* means a * b *)
| Divide of expr * expr (* means a / b *)
| Value of string (* "x", "y", "n", etc. *)
| Number of int ;; (* I added this one *)
Then I added a reduce function to reduce expressions:
let rec reduce e =
match e with
Times( Number x, Number y) -> Number ( x * y)
| Times( e1, Number y) -> Times( (reduce e1) , Number y)
| Times( Number x, e2) -> Times(Number x , (reduce e2))
| Times( e1, e2) -> Times ( (reduce e1), (reduce e2))
| Plus( Number x, Number y) -> Number (x + y)
| Plus( e1, Number y) -> Plus( (reduce e1) , Number y )
| Plus( Number x, e2) -> Plus( Number x , ( reduce e2) )
| Plus( e1, e2) -> Plus ( (reduce e1), (reduce e2))
| Minus( Number x, Number y) -> Number (x - y)
| Minus( e1, Number y) -> Minus( (reduce e1) , Number y )
| Minus( Number x, e2) -> Minus( Number x , ( reduce e2) )
| Minus( e1, e2) -> Minus ( (reduce e1), (reduce e2))
| Divide( Number x, Number y) -> Number (x / y)
| Divide( e1, Number y) -> Divide( (reduce e1) , Number y )
| Divide( Number x, e2) -> Divide( Number x , ( reduce e2) )
| Divide( e1, e2) -> Divide( (reduce e1), (reduce e2))
| Value v -> Value v
| Number n -> Number n ;;
OK, so if I were doing this in Ruby somehow, I'd think, "you know,
that seems like a lot of duplication" and I'd metaprogram it so that
(if pattern matching were possible in standard Ruby) each of those "|"
options could be generated from some simple one liner given a list of
constructors for the expr type and a list of operators. But camlp4
it's overkill for this sort of thing... In scheme you could write
some sort of macro (though, pattern matching isn't built into scheme
either, nor is strict typing). If I had a more complex type with many
more constructors and more matches I'd be tempted to make some sort of
Ruby DSL to generate this stuff ;-)
Also, is Template Haskell closer to MetaOcaml than it is to camlp4?
Phil
PLT Scheme (and probably other Scheme implementations) has pattern-matching.
In fact, the match code was just recently re-written for better performance.
-- Paul
data Expr = Prim Op [Expr]
| String String
| Int Int
deriving Show
data Op = Plus | Minus | Times | Divide
deriving Show
prim_op op [Int x, Int y] = Int (op_val x y)
where op_val = case op of
Plus -> (+)
Minus -> (-)
Times -> (*)
Divide -> div
eval e = case e of
Prim op es -> prim_op op (map eval es)
_ -> e
Hope this helps,
Iavor
OK, I've got all of the above in OCaml as:
type op = Plus | Minus | Times | Divide ;;
type expr = Prim of op
| Value of string (* "x", "y", "n", etc. *)
| Number of int ;;
let prim_op op tup =
let op_val = match op with
Plus -> ( + )
| Minus -> ( - )
| Times -> ( * )
| Divide -> ( / ) in
Number( (op_val (fst tup) (snd tup)) ) ;;
(* try it *)
prim_op Plus (2,3) ;; (* -> 5 *)
But I'm a bit stumped as to how to translate this eval from Haskell to Ocaml:
> eval e = case e of
> Prim op es -> prim_op op (map eval es)
> _ -> e
>
any ideas?
Phil
>
> Hope this helps,
> Iavor
>
Here is the version on ocaml. Your version was almost correct. What I changed:
1) added the argument list for prim ops in "expr"
2) changed the function "prim_op" to work with lists instead of pairs.
Actually, you can do it either way, lists are a bit more general
because you could have prim-ops with different arities.
Hope this helps,
Iavor
type op = Plus | Minus | Times | Divide ;;
type expr = Prim of op * expr list
| Value of string (* "x", "y", "n", etc. *)
| Number of int ;;
let prim_op op [ Number x; Number y ] =
let op_val = match op with
Plus -> ( + )
| Minus -> ( - )
| Times -> ( * )
| Divide -> ( / ) in
Number(op_val x y ) ;;
(* try it *)
prim_op Plus [Number 2; Number 3] ;; (* -> 5 *)
let rec eval e = match e with
Prim (op,es) -> prim_op op (List.map eval es)
| _ -> e ;;
(* try it *)
eval (Prim (Plus, [Prim (Times, [Number 2; Number 3]); Number 7])) ;;
Phil