Hacker News new | past | comments | ask | show | jobs | submit login

What reasons are there for choosing OCaml over Haskell, either from a learning perspective or a practical one?



OCaml is more of a multi-paradigm language than Haskell. It's not purely functional, so you can easily fallback into imperative code if you need (you can use mutable variables, I/O, mutable arrays, hashmaps, for loops, while loops, etc.). It's also object-oriented (though this feature is not widely used) and has a very powerful module system that few other languages can compare to.

What I like about it from a learning perspective is that it makes a transition into functional programming much simpler than it would be with Haskell, where you have to completely change the way you program from the very beginning.


haskell is great at being imperative too look at chris done's work on xml parsing haskell and c; nice example


I'm not sure why you're being downvoted. I don't know Haskell, but I had a look for the parser you mentioned and it does appear at first glance to use a fairly imperative-looking style, with loops and pointers into mutable data:

https://github.com/ocramz/xeno/blob/master/src/Xeno/DOM.hs

I would be interested in an analysis of this code from anyone who actually does know Haskell in case I'm misreading it.


Ocaml is a bit easier to reason about w.r.t. performance (time/space complexity), and the code is a bit clearer if you're coming in cold after not having seen parts of a codebase for a while. Spent ~10 years at a Haskell shop, and currently at an Ocaml one, and was a Standard ML hacker prior to the Haskell job. Done some F# in there too, although for the most part that just feels like ocaml w/ some cleaned up syntax and a nice interop with the rest of the .net ecosystem.

From a nontechnical perspective, some changes in the Haskell community and ecosystem also turned me off on it starting around 2011, and I find the ocaml one to be a bit more up my alley.


Simplicity. Strict evaluation. Functors (first-class/higher-order modules), although Haskell is trying to get there with Backpack too.

Good idea to learn both, anyway :-P

Edit: compilation speed too, huge difference


I believe OCaml isn’t as strict about side-effects as Haskell, so if you don’t want the side-effect ceremony Haskell sort of forces on you, OCaml might be a good choice. Also, OCaml is strict by default and had a fairly good compiler.


> I believe OCaml isn’t as strict about side-effects as Haskell, so if you don’t want the side-effect ceremony Haskell sort of forces on you, OCaml might be a good choice. Also, OCaml is strict by default and had a fairly good compiler.

Probably anyone who's interested here knows, but it may be appropriate to point out that you are using the word 'strict' in two different senses, first in the informal sense of being restrictive, and second in the formal sense of strict evaluation (which is why it makes sense to say that OCaml is less strict, and yet strict by default).


Yeah, I didn't even think about that when I wrote the comment, but it occurred to me later that that might be confusing.


Is there any convention for denoting which functions in OCaml have side effects?


Not really, but the documentation will usually tell you. Also, at least in Jane Street’a libraries, exceptionful functions always end in _exn. So for example there is List.find and List.find_exn


Some people append `_exn` to names of functions which can raise exceptions; that's about it.


I don't think it's a strict convention, but it's common to see (a block of) imperative statements with side effects enclosed in:

begin ... end

It's ugly and stands out in its awkwardness, almost as if by design, with the compiler saying: "I will let you do this, but do think about it some more and try and come up with something more elegant."


I don't know, I don't write it very much.


Considering neither is the language I use for work, but just as a hobby, I often forget how to write code in these languages after a while. The amount of time to get back on track to write idiomatic OCaml is almost instantaneous as opposed to Haskell.

Disclaimer: I've written far more OCaml code than Haskell, so maybe my opinion may be biased.


Yes, writing Haskell definitely takes a mental context switch. You kind of have to abandon the traditional style of programming in order to transition into it. Pretty similar to what writing Prolog feels like for example. In contrast, it seems like there's a more direct line between languages like OCaml/Lisps versus C/Java.


I like to liken it with muscle atrophy. Gotta get my weekly fix of Haskell to maintain it!


Modules and parametric modules, subtyping (polymorphic variants [1] and objects), proper records, classes making bindings to OOP APIs natural, strict evaluation, ppx extensions [2].

[1] http://keleshev.com/composable-error-handling-in-ocaml

[2] https://victor.darvariu.me/jekyll/update/2018/06/19/ppx-tuto...


Although it's very brief, they touch this topic in the intro: "OCaml does a great job of clarifying and simplifying the essence of functional programming in a way that other languages that blend functional and imperative programming (like Scala) or take functional programming to the extreme (like Haskell) do not. Having learned OCaml, you'll be well equipped to teach yourself any other functional(-inspired) language."

This course is for teaching students who know how to program but are new to functional paradigm. The way I understand the above is that OCaml is impure, so it's easier to have some parts in imperative style to get unstuck and move forward at first. That may reduce frustration for some students. Then over time, as the functional approach sinks in, you move to a purer style (with sometimes imperative parts, but well encapsulated). Haskell would be more like "let's jump at the deep end of the functional pool" --- which can work for some too.


I had hoped to use Haskell for my company, but found it much too complicated. OCaml skips a great deal of the complexity of Haskell, while still having the advantages of a static functional language. I find it exceptionally practical.



But Haskell is also beautiful, in much the same way ML is, and arguably other ways besides.


strictness by default, and a slightly more pragmatic way of life. Haskell quickly goes into categorical like composition (Traversable . Lens . Foldable). I think for the average population this is too quick. Ocaml feels like solid battle tested fast typescript (pardon the caricature :).


I'm currently developing a web app with a Haskell backend and a ReasonML (OCaml with a different syntax) frontend. I'd been interested in ReasonML for a while and so far it's been a great experience, but overall I wouldn't say I prefer it to Haskell. I've been using Haskell for many years and so the simplicity advantage isn't there for me. I also miss strongly some of the major Haskell conveniences like generic programming, type class derivation, higher kinded types, and yes Monads. I'm not a huge fan of the OCaml record system as it frequently gets confused and requires type annotations. In fact I've generally found OCaml to be substantially worse at type inference than Haskell, requiring frequent type annotations and cluttering up the code. Haskell's learning curve is steeper, but it is simpler in some ways, especially once you're familiar.

I think where ReasonML/OCaml wins hands-down is its compiler. Bucklescript (and I've heard similar things about other compilers, but can't vouch for it) is lightning quick, and the community has gone leaps and bounds to make it super easy to bootstrap (including with create-react-app). GHC can do amazing things but it's not the fastest out there, and the compiler for the JS backend is abysmally slow. The code Bucklescript produces is very high quality and performant. The library ecosystem is reasonably strong and I expect (but haven't done much testing) that because of the strictness and relative simplicity of the language, library code would tend to be pretty performant and easy to use. I've never found myself in OCaml wondering what string type I should use, or attempting to parse some absurdly complex type hierarchy in a library.

I think for a frontend project, to most programmers I would recommend ReasonML. For one thing, I think even most without experience with FP would find ReasonML to be a giant improvement over Flow (which infuriates me as a type checker), and it doesn't take a ton of time to learn. ReasonReact is a pretty sweet library and I prefer it to React even setting aside language choice. Compared to Haskell, its strictness means it doesn't require a special runtime, generate slow/impenetrable code, or hog tons of resources -- all things that are issues in frontend Haskell. For those who really want to use Haskell on the frontend I'd recommend PureScript instead (also you get the bonus of a kickass record system).

For backend, I think OCaml will get you up and running sooner, but in the long run you're going to find yourself missing the type system and language features Haskell has. GHC's speed on the backend is tolerable (especially if you use nix), and I think Haskell is competitive in performance to OCaml (perhaps better with optimization). Most importantly, I think Haskell is second to none when it comes to correct implementations of business types and logic, creating powerful and reliable abstractions, and eliminating boilerplate, and I think that forms a greater advantage in backend code.

EDIT: this turned into quite the essay...


> quite the essay

Our lucky day :)

Was there a reason you didn't go the Haskell -> Js route? Less mature but benefits of keeping the same language would have trumped the downsides? Besides compilation speed you mentioned...

I'd love to hear more on the compile to Js scene from someone experienced like you. Do you have a 'weblog'?

Edit: Have you tried Scala.js by any chance?


Hah, no I don't have a blog, but I'm glad you enjoyed reading it! :)

I touched on this a bit, but the main thing is the compiler experience. I've written apps in Haskell compiled to JS before; specifically I was using Miso. While I very much enjoy writing Haskell -- that part was great -- the compiler is very slow, the binary is huge, and the generated code is completely incomprehensible. There are a few other disadvantages, such as runtime bulk, speed, laziness and the multitude of string types as well. Bucklescript is _so_ much faster than ghcjs and the tooling fits neatly into an established workflow (i.e. webpack, create-react-app etc). It compiles almost as fast as ES6, it has a built in code formatter, it supports JSX natively, etc.

That, plus I had been curious about trying OCaml for a while and I figured why not.


> Have you tried Scala.js by any chance?

Scala.js is amazing, but it lacks lazy loading mechanism popular in TypeScript/JavaScript ecosystem -- basically you can't create a set of "tiny" modules (since the Scala compiler + standard lib are integral to each exported module), so you wind up creating a single "app.js" that contains the world (or perhaps 2 modules, one for the frontend and another for the backend).

It works but it's not ideal -- would be amazing to be able to mixin a standalone scala compiler + standard lib module that lazy loaded modules could depend on.


Can I ask what you compare it with when you say amazing? I too liked it a lot but don't know what the state of the art is elsewhere.

Pardon me for wading through your history but you seem to have used Buckle script too- and claim that it has insane compilation speed and tiny Js size - (which would translate to a one time perf gain in download/parse/exec). How is the performance difference over the course of application? Would you still use Scala.Js if you didn't use Scala on the back end?

Also, why not create multiple scala-Js projects to do what you're looking to do? You'll have to fight SBT but if you die you're a martyr and if you survive you get to fight it another day...


> Also, why not create multiple scala-Js projects to do what you're looking to do?

That won't help. Scala.js banks heavily on whole program optimization to reduce the size of emitted Javascript. Two independent Scala.js modules will contain redundant code including likely upwards of 100kb of Scala standard library (collections, futures, etc.)

There is an issue about webpack-style code splitting support for Scala.js somewhere on github, and Sebastien said it's doable with the current architecture, so we'll likely get that eventually, but it's not there yet.

I do love working with Scala.js - great language and great interop with JS.


For all the efforts to put Haskell on the frontend, they're all lacking in some way or another and full of land mines.

Let GHC do what it does best; run it on the server.


Haskell is still a pretty awesome language tho, so using it on the frontend is pretty sweet. Nothing about the language is problematic here (with the possible exception of laziness which is one reason why I personally prefer purescript). And Miso is actually pretty awesome and easy to use. The main issue is with tooling, especially the slow compiler. My hope is that a wasm backend will be developed soon, hopefully along with subsequent speed improvements. Compiling a ton of non-DOM library code to obscure JavaScript makes no sense. Not to discredit the work of the ghcjs team, which created something pretty awesome and useful, but most of that would make a lot more sense in wasm. Beyond that, it needs bells and whistles like webpack integration and source maps. But really, despite its warts, it is quite usable for frontend and shouldn’t be discounted.


Thanks for sharing this!

Have you ever considered js_of_ocaml (https://github.com/ocsigen/js_of_ocaml)? What were your reasons for choosing ReasonML?


Mainly I was more interested in ReasonML than OCaml (syntax- and tooling-wise), and the recommended toolchain there is bucklescript. I'm not really aware of the differences between bucklescript and js_of_ocaml, or how easy it would be to switch, but I have no complaints with bucklescript so far.


> I also miss strongly some of the major Haskell conveniences like (...) Monads.

Could you elaborate? Ocaml has monads? Do you mean convenient do-notation for monads, or something else?


Monads in Haskell are an entire ecosystem, including wonderful things like Traversable and MTL style typeclasses, and I would need to see these ported before I could be convinced that Ocaml has monads (as anything more than a limited toy). I've tried to do extensive ports in the past, but given up, last time because I hit limits on Ocaml's ability to define mutually recursive functors.

In general, I've found programming with monads in Ocaml far less pleasant than Haskell, owing to the lack of overloading. The module implementation of monads requires you to functorise your code and apply a functor for every monad you want, while in Haskell I just (>>=) and the type system figures out what I meant. The verbosity makes me want to avoid them entirely.

The only other popular functional programming language I've seen which has a proper zoo of monads is Scala, which, I think by no coincidence, supports implicits and supports higher-kinding without having to functorise.


You can define monads in OCaml just fine using the module system, but there's no do-notation. I think there is a PPX extension to give that, though.


The ppx extension in question is called let-syntax, but also 4.08 is almost here and has built-in support for something similar.


PureScript is my favorite/preferred frontend language right now; I just wish it had a few more folks to round out the userbase's numbers.


I did one small pedagogical project in PureScript. As a language, I really like it; in fact I'd prefer it to Haskell in many ways. The compiler experience is good, if not great. Compile times are a lot slower than Bucklescript but a lot faster than ghcjs. Performance is definitely worse, but for many apps I think it'd be fine (and you can always FFI out...). There is a webpack loader for it, although I've had some issues trying it. I've found the syntax to be quite confusing though, even coming from a Haskell background. Parser messages are vague and tracking down the bug can be very frustrating. Also not supporting things like trailing commas is lame (but the same in Haskell). Type errors are also often difficult to understand (even compared to Haskell).

I think overall it needs more development, in particular in regards to UX and integrating into a modern development workflow. I'm excited to see its progress :)


Agree with everything you said, compile times and perf and tooling in PS is not great. I guess I just value safety and expressiveness more than the other things. For some reason, I really do not care about slow compile time; it just doesn't bug me, but I admit it is slow. I think GHC conditioned me to just roll with obscure error messages, haha - learning some rust and the detail put into error messages honestly surprised me (of course the type system is not as flexible in many ways too, though, so of course the errors will be more concrete).


I normally wouldn't value those things as highly but I find that compiler speed and tooling makes a huge difference to me for front-end dev specifically, because I'm constantly doing the code->compile->use cycle, and a slow compiler is a pain there. But I'd happily use PureScript again, and am still considering returning to it for this project at some point.


What else have you used can I ask?


Honestly, I tend to avoid compile to js langs, so not much other than typescript. I would like to try bucklescript and F#'s Fable. Not interested in scala.js or clojurescript just because I'm not invested. Elm is too locked down and inexpressive. Reasonml just seems superfluous.


Ocaml has 100% less bikeshedding and no propensity for unending puritanical holy wars. It's a language for getting things done, as opposed to thinking about finding a way to do something that satisfies an obsessive compulsive desire to eliminate 100% of sides effects for no practical reason.


Except we've been waiting how many years for actual multicore support and ad-hoc polymorphism (or anything approaching it)...?

No, OCaml really isn't a language where things move forward; quite the opposite.

Also, if you had actually written any Haskell code you'd know it's not about eliminating any side effects, it's about denoting them in the type system. Your comment reeks of someone who hasn't actually used either of these languages.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: