|
![](/i/fill.gif) |
Invisible <voi### [at] dev null> wrote:
> Problems become apparent almost immediately. I had a look at the Great
> Language Shootout, where I found Ocaml getting royally OWNED by both C
> and C++, mainly because both of these used all four CPU cores, while
> Ocaml apparently can't. Ocaml supports multiple light-weight threads,
> but because the garbage collector isn't thread-safe, all Ocaml threads
> run in a single OS thread - i.e., on a single CPU core.
>
> Haskell, of course, runs your threads on several cores, like you'd
> expect. (Unless you specifically ask it not to because you're trying to
> interface to external C libraries that use thread-local storage.)
>
> Of course, even Haskell currently has a parallel but not concurrent GC,
> and in particular to perform a GC cycle you have to wait for all Haskell
> threads to stop. (They can only be stopped at certain points.) This can
> cause large program slowdowns, where one thread is in a tight loop and
> won't stop, and all the other threads are paused waiting to start a GC
> cycle.
You're right. The lack of concurrent GC is the single most important issue to
be fixed today, even Jon Harrop would tell that. That's why you're seeing today
C and C++ beating OCaml real hard. Because just a while ago -- when OpenCL,
OpenMP and other easily-parallelizing toolkits for C/C++ compilers weren't
generally available -- OCaml programs usually sported similar performance to
C/C++ and were also much clearer and shorter.
Eventually, it should get up to date.
> But hey, all of this isn't really to do with *Haskell*, but rather with
> *implementation*. Specifically, I'm talking about GHC. Other
> implementations do exist. [Most of them don't support SMP *at all*
> though.] You could write another implementation, or fix GHC, and the
> above drawbacks would go away.
yeah, but it's probably a very difficult issue.
> Then I started to look at the syntax. It's *mostly* identical to
> Haskell, but with a few differences.
Haskell is mostly identical to ML, which is OCaml's direct ancestor. Miranda
the most direct ancestor to Haskell was based on ML's ideas.
> In Haskell, I can write
>
> foo = 5
>
> In Ocaml, you must write
>
> let foo = 5
>
> Small bit of superfluous chatter there. Still, I guess it makes the
> syntax more consistent. Slightly. But then we get to the next
> abomination: In Haskell, I can say
>
> foo = bar foo
>
> but in Ocaml, you must say
>
> let rec foo = bar foo
let and letrec are common constructs in Scheme as well. They introduce scope
and recursively defined scope.
> Yes, that's correct, you have to manually tell the compiler that you're
> making a recursive definition. WTF? What, it isn't trivial enough for
> the compiler to detect this all by itself?
No, it's not trivial (oh such common word) at all. Which is also why you don't
have many compilers for Haskell, but you get quite a good lot of good performant
compilers for both ML (Jersey ML, MLton, OCaml) and Scheme (Bigloo, Chez,
Gambit, Stalin etc).
> Another puzzling thing is that Ocaml appears to use a layout rule
> similar to Haskell [not that the tutorial I'm following bothered to
> point this out], and yet it still requires explicit semicolons anyway.
> (??) And there's a set of fairly complex rules for when you must and
> must not write them. (?!?)
I don't like all the semicolons either. And the +. *. operators for
floats/doubles, but hey, at least these help on performance.
> In Haskell, you can say "Set Integer" or "Set String" or "Tree Integer"
> or whatever. Apparently in Ocaml you have to say this backwards:
> "integer tree" and so forth.
Being used to Pascal as well as C, I don't see the issue here. It's just a
different way to state something: "a set of integers" or "an integers set".
> Haskell uses the convention that type NAMES must begin with a capital
> letter, while type VARIABLE must begin with a lowercase letter. Ocaml
> uses the arguably superior convention that type variables start with an
> apostrophy.
I prefer Pascal and Scheme instance on the significance of names rather than
case. (though the latest Scheme standard has gone to case-sensitive lameness)
> Which reminds me - in Haskell, "Char" is a 32-bit Unicode character.
> Ocaml makes the mistake of using an 8-bit ASCII code. (But apparently
> there are libraries to "work around the problem".)
It was not a mistake before Unicode showed up, it was common-sense, specially in
a performance-conscious programming environment.
> Haskell has algebraic data types. Every Haskell type is nominally an
> ADT. (Although in the case of "Int32", it's an enumeration type with
> constructors named "0", "1", "2"...) All types follow the same uniform
> structure.
>
> Ocaml, on the other hand, has "records" which are like "{field1=5,
> field2=true, field3="hi"}", and "variants" which are like Haskell ADTs.
> And they're apparently not the same thing. You can see this when you
> define one:
>
> type recordX = {field1 : int, field2 : string, field3 : stuff}
>
> type variantY = Thing of int * string * stuff | OtherThing of char * char
>
> So "records" use named fields, but have only a single (unamed)
> constructor, while "variants" allow multiple constructors, but use a
> wierd syntax for defining the fields - a syntax resembling tuple types,
> actually. WTF?
I don't know enough of OCaml to say this with 100% certainty, but I'd say it's a
design choice geared at, again, performance. Just like C++ got plain structs
against the more heavyweight classes.
> Haskell makes the rather illogical choice of using "--" as the start
> marker for a comment. (Great. So I can't use that as a name then!) But
> Ocaml uses the even stranger choice of "(* ... *)". Which means that you
> can't write "(*)" to mean the multiplication function, you must write "(
> * )" [with spaces] to prevent it parsing as a comment.
Why would you write (*) 2 3 in OCaml when you can simple 2*3 or 2*.3? (or even
in Haskell, except to make it look like Lisp ;)
(* this comes from Pascal and BTW,
it spans several lines, which -- doesn't *)
Do you know what the Haskell multiline comment marker looks like? I'll wait for
the answer.
> Also, Haskell uses "++" for string (and list) concatenation. But Ocaml
> inexplicably uses "^" instead. (Haskell uses both "^" and "**" to mean
> exponent - but one is with an integer exponent and the other is with an
> arbitrary exponent. No, I can never remember which is which.)
Different syntaxes coming from different language heritages.
> In Haskell, if I want to compile a multi-module program, I say
>
> ghc --make MyThing
oh, you didn't get the fun times when GHC would compile down to C files and then
you ran the whole C-stack build process on your own, did you? You missed half
the fun, my friend...
> In Ocaml, things are not so easy. Apparently YOU have to manually
> determine the correct order in which to compile things, and issue all
> the commands in the right order. (Or just use make.) You even have to
> compile and seperately link things - and tell the compiler whether it's
> supposed to be compiling or linking, and manually tell it what libraries
> to include. *sigh*
OCaml development is not as large or hip as Haskell's, so they have to make use
of whatever is ready for them, which means things like make.
> It gets even better though. If you write a source file and compile it,
> *everything* inside is public. If you don't want that, you have to
> *manually* copy and paste the names of the public stuff into an
> "interface file", and you apparently have to manually write in the
> correct type signatures. (So much for "Ocaml does automatic type
> inference".)
well, it does, but just as in Haskell, the H-M type system some times has to
sort out type ambiguities that may arise. All but the simplest of modules don't
have type signatures. The interface files just collect such signatures, which
is good because it's the only thing I have to go through instead of wading
through large source code just to lookup for signature or, worse, try to
understand from source code what the hell a function is expecting for parameter.
> You then have to insure that this file is compiled at the
> right moment - i.e., after the corresponding source file is compiled,
> but before anything depending on it is compiled.
That's why a Makefile is so useful. ;)
> Again, in Haskell you just write a list at the top of the source file
> saying what things should be public. The compiler does the rest. Even if
> you're manually running the compiler stages for some reason, the right
> thing happens. The object file and interface description are generated
> automatically in a single pass, and dependencies won't compile until
> these exist.
Good for Haskell that its large developers have recreated make inside it, but
not everyone can afford that.
> It is *claimed* that you can compile Ocaml into a library that can then
> be linked into programs written in arbitrary other languages (C or
> whatever).
It can, because source files are compiled into native object code.
> If so, that would certainly seem like an advantage. OTOH,
> Haskell can supposedly do this too - it's just that it'll be a bloody
> huge library! (Because it will contain a copy of the entire Haskell RTS.)
yes, pragmatism was the main force behind OCaml.
Post a reply to this message
|
![](/i/fill.gif) |