Does anyone know why OCaml gets compared to Haskell so often? It sounds like OCaml doesn't force a purely functional paradigm on you, so how is it any more functional that a number of good scripting languages (Python, Ruby, Peal, etc)?
Does anyone know why OCaml gets compared to Haskell so often? It sounds like OCaml doesn't force a purely functional paradigm on you, so how is it any more functional that a number of good scripting languages (Python, Ruby, Peal, etc)?
I don't think "functional" means a whole lot. Many languages with lightweight, first-class lambdas like to jump on that bandwagon by implementing map/fold/scan/take combinators on lists, sometimes even lazy ones, but that whole game is just a sideshow to the real meat of what makes Hindley-Milner typed languages with ADTs quite fun to work in.
> :t (+ 5)
(+ 5) :: Num a => a -> a show . read > :t read . show
read . show :: (Read c, Show a) => a -> cThe "internal, ambiguous type" matters when you try to actually invoke (show . read) on some String. If you want to actually use that function, you're stuck inserting a type annotation, which would lead many people to say that (show . read) is not "inferred just fine."
There is no internal ambiguous type. It is not a concrete type, it is a type variable. But it is inferred just fine. It is (Read a => a).
>which would lead many people to say that (show . read) is not "inferred just fine."
Even if you were to erroneously say that, it isn't type classes that is the problem.
I'm pretty sure it is. For example, see section 3.7 of "Type classes: an exploration of the design space" by SPJ et al.
All the other features are orthogonal and specialized.
A := B
Then all values that could be bound to B could be bound to A also (so B <= A), but if the other way was also taken (B = A), then
A := C
Would imply that B = C, which leads to all sorts of safety problems...so you don't do that. At the end of the day, to make HM work with assignment, you need something like ML's "value restriction" that prevents full unification between A and B.
let test r =
r := `A;
r := `B;
r := `C
r gets unified with all of `A, `B and `C: no problem. let r = ref []
Here r has type 'a list ref (reference to a list of 'a where 'a is unknown). r := ["hello"]
r has type 'a list ref, := has type 'a ref -> 'a -> unit, and ["hello"] has type string list, so it works (if we instantiate 'a with string). let n = 1 + (List.head !r)
1 has type int, + has type int -> int -> int, and we can type (List.head !r) as int since we can type !r as int list since we can type r as int ref list (this time instantiating 'a by int).So, we just added an int and a string and the program will probably crash. What's wrong is that every line is correct but because of the mutable store, the program as a whole is incorrectly typed.
The solution is to generalize only a subset of all syntactic constructs. The historic solution in Ocaml is to never generalize expressions that may allocate memory (that's the "value restriction") . For example, a function application (like f x, or ref []) may allocate, but a variable or a constant (like x or 1 or []) can not. That's why [] has type 'a list but ref [] has type '_a list ref ('_a can be unified only once, so in the above example an error would occur at the "let n").
import Data.IORef
main :: IO ()
main = do
r <- newIORef []
writeIORef r ["Hello"]
x <- readIORef r
print $ x + 1
return ()
The reference is bound by "r <-", ie a lambda (as this desugars to ">>= \ r ->"), and lambdas are never generalized (even in ocaml).I think that the reason why it works is that because there is no way to let-bind r except with a toplevel unsafePerformIO.
C++ might look like this:
void do_something(bar_t & bar)
{
...
bar.foo(...);
bar.baz(...);
auto something = bar.get_something();
...
}
The equivalent Ocaml might look like this: let do_something bar =
...
Bar.foo bar ...;
Bar.baz bar ...;
let something = Bar.get_something bar in
...
The situation is similar when dealing with structs and tends to be ever worse when dealing with generic code (although C++ only has duck typed generics until concepts comes along).Subtyping isn't a good organizing principle for code reuse from a type-safety or human-sanity perspective. Typeclasses and composition are better.
You should give Haskell a whirl.
Edit: Also, sub-typing tends to make a lot more sense in a language with value semantics, such as C++, than it does in a language like Haskell and isn't necessarily about organizing code.
For example, the base member of Composed is not a pointer as it might be in a language with reference semantics:
struct Base
{
int i;
};
struct Derived : Base
{
bool b;
};
struct Composed
{
Base base;
bool b;
};I seem to recall (incorrectly, apparently) that there is a common thread going back to Standard ML for both OCaml and Haskell. Appears, Haskell goes back to Miranda which borrows from SML -- but it's not entirely incorrect to say that both OCaml and Haskell are built on the shoulders of SML. My take is that OCaml was seen as a way to make a "useful" MetaLanguage, fit for more than experimental language implementations -- while Haskell was conceived by some crazy people that didn't think it was hard enough to get any useful work done in SML ;-)
Now, Haskell has evolved into something that actually is useful, and the biggest difference AFAIK is that Haskell leans towards strict and lazy than OCaml.
As they are both "modern" MLs, it's natural to compare them -- why Haskell isn't compared more often to SML might just be that there are a few programs actually written in OCaml that people are aware of ;-)
The basis of OCaml is functions that transform one thing into another. The basis of Ruby is objects that encapsulate some state and send messages to other objects to get them to change their state.
Several of the data structures in the stdlib make good use of sharing to reduce the cost of operations - Set.union is a particularly good example. map, however, is not the sort of operation that leads to sharing.
Because both belong to the ML family branch of programming languages.
Second, ocaml is a multiparadigm language for real, and with a focus of functional first. Python, ruby, perl, etc are procedural/OO languages that have map and filter. It is a huge pain and tons of extra code to write a program in functional style in python, it is lacking basically everything. It is normal to write a program in a functional style in ocaml.
If you learn haskell first, ocaml will serve no purpose for you. But for someone coming from imperative land, learning ocaml can be a helpful half-way house on the way to haskell.
One big question informing the choice is "do I want to program primarily lazily or primarily eagerly?" Another is "is time to achieve system performance a big factor in success?"
If eager, performance-eager -> Ocaml If lazy, performance-lazy -> Haskell
You pose two questions, one of which is effectively irrelevant, and the other I believe is based on an incorrect assumption. Maybe 5% of code the evaluation strategy matters. It makes no difference whether you are adding strictness for 2% of your code or adding laziness for 2% of your code.
The performance question I think is a misconception. Do you have any evidence to suggest it is easier to write fast code in ocaml? I've never found a person who has used both languages and felt that was the case. I've only found people without haskell experience believing that via second (or third, or fiftieth) hand rumors.
Ocaml offers two things over haskell. One, imperative constructs. This matters for people making a transition to functional programming, but not for people who've finished that transition. Second, the compiler is fast. I don't mean generates fast code, ghc does that too. I mean it generates code quickly. This is an annoyance with ghc, no question.
Haskell offers a lot over ocaml. A useful standard library. Cabal and hackage. Parallelism done right, out of the box (super cheap green threads multiplexed over a pool of OS threads). Tons of libraries that don't exist in ocaml, everywhere from attoparsec and aeson, to binary and lenses, pipes-concurrency and STM. A community that is ten times the size of ocaml's.
There are good reasons it has gone from ocaml having the larger community to haskell dwarfing ocaml in community size, language usage, library availability, etc. in the last decade.
I find it much easier. To give one example: I recently had to write some code that shuffles arrays based on a PRNG. In OCaml, one can simply use a mutable array and a PRNG that uses a mutable variable.
In Haskell, efficient array mutation is possible, but you have to do it in the ST or IO monad. So, in a pure function you'll want to runST an expression in the ST monad. But then you need to thread the 'state' of the random number generator in function calls, or use a State-like monad. If you use a state monad, you have two monads and will probably use a monad transformer.
Writing the equivalent Haskell code is much more work. But on the other side, Haskell keeps you more honest. The end result is that in Haskell, it is guaranteed that the end-result is pure (if you don't use unsafePerformIO of course). In OCaml it's only by convention.
Which is better depends on what you want, convenience or safety. Personally, if I have to choose between OCaml or Haskell, I'll choose the latter. There are already plenty of languages that are pragmatic and less strongly typed. For me, OCaml provides relatively only advantages over strongly-typed imperative languages that support closures, etc. Haskell on the other hand, provides an amount of type-safety that those languages do not provide, while still being usable (both as a language and in terms of the library ecosystem).
Ok, but your anecodes + my anecdotes = still just anecdotes. To support the claim that it is easier to write fast code in ocaml, we need to find evidence.
>Writing the equivalent Haskell code is much more work
I have not experienced anything like that, despite having much more experience with ocaml than with haskell. You are imposing limitations on yourself when using haskell and then saying haskell is imposing them. Every ocaml function is in IO, it just doesn't provide type information to tell you that. So doing the same thing in haskell is doing it in IO, which requires no special effort at all. Even if you choose to add a purity restriction on yourself, adding "runST $" does not seem like a lot of work to me.
The first post in this blog series had a simple test (really just testing start-up time), where Haskell and OCaml were very similar. But in the second post (http://roscidus.com/blog/blog/2013/06/20/replacing-python-ro...) with a slightly longer test-case, OCaml was twice as fast as Haskell.
But that's the point right. He did the same for OCaml and got faster code. Obviously you can write fast code in Haskell, but that is not the same as it being easy.
No he didn't. He took the time to learn ocaml.
>Obviously you can write fast code in Haskell, but that is not the same as it being easy.
The closest thing to evidence I can find suggests that it is no more difficult to write fast code in haskell:
http://benchmarksgame.alioth.debian.org/u64/benchmark.php?te...
Not before writing his initial benchmarks, which is what we're talking about.
> The closest thing to evidence I can find suggests that it is no more difficult to write fast code in haskell:
> http://benchmarksgame.alioth.debian.org/u64/benchmark.php?te....
That measures ridiculous highly tuned implementations of the benchmarks, often written by the creators of the languages themselves. It contains absolutely no evidence of how hard it is to write fast programs in a language.
Besides, I'm pretty sure citing the language shoot-out is an automatic disqualification in any argument about language speed.
Yes, he did. Try talking to him.
>That measures ridiculous highly tuned implementations of the benchmarks
So, fast code. Which is what is at question.
>It contains absolutely no evidence of how hard it is to write fast programs in a language.
There is both lines of code, and actually looking at the code itself. Both of which make it appear that writing fast code is no more difficult in haskell than in ocaml.
>I'm pretty sure citing the language shoot-out is an automatic disqualification in any argument about language speed.
I'm pretty sure the language shoot-out is of greater value as evidence than personal anecdote is.
No the question is about whether fast code is easy to write, if it has to be highly tuned then it is not easy to write.
> I'm pretty sure the language shoot-out is of greater value as evidence than personal anecdote is.
Actually, I think that the shoot-out causes a lot of harm to people's attempts to understand whether a language is fast or not.
When people ask: "Is language X fast?" what they mean is "if I write my programs in it will they be fast". They do not mean "is the highly tuned code of an expert fast".
The question of whether a language is fast is about whether code written in the natural idioms of the language is fast, not about whether you can coerce the compiler into producing the precise assembly code you are aiming for. If you are going to do that you might as well write the assembly code directly and call it using an FFI. Many implementations on the shoot-out bare no resemblance to the code people naturally write in those languages.
The fact that this code is fast tells you nothing about whether idiomatic Haskell is fast. wrong evidence < no evidence.
The question was about difficulty, not a subjective idea of what idiomatic code looks like. Are you seriously claiming that the average haskell example there is more difficult to write than the average ocaml example? If so, just say that. Trying to redirect the discussion back to your subjective preferences is not productive.
And `inlinePerformIO` is much more unsafe, because it requires that you do no memory allocation inside it. This property is specific to the Haskell implementation, and is certainly not easy to guarantee.
I certainly tried to treat them equally. If I cut-and-pasted from the web more often for the Haskell, it's because I got stuck more often.
For example, I didn't need to search the web for how to read argv[0] in OCaml. It's just Sys.argv.(0). Easy. Would you really expect a beginner to figure out the Haskell version on their own?
https://www.haskell.org/ghc/docs/latest/html/users_guide/rel...
The second link is to Environment.hs, which would have solved my problem, if I'd known what I was looking for. I think I'd have just clicked Back when I saw it was library source code, though.
The third link is http://hackage.haskell.org/package/system-argv0-0.1 - which says "Use this instead of System.Environment.getProgName if you want the full path, and not just the last component."
(note: technically, my code was still the correct solution, since 0install targets Ubuntu 12.04, but yes ideally I would have found that newer versions did support it more simply)
I've had the exact opposite experience. I write my Python code in a functional style by default. I use mutation as an exception rather than the rule. I find my code to be much more terse overall. When used effectively I find functional Python requires less code, not more as you imply.
I think you are writing what I would call imperative code that uses some functional constructs where it is shorter. No doubt that is shorter than sticking entirely to imperative code, but it is a far cry from writing a program in functional style which requires that you not use imperative constructs.