Hacker News new | ask | show | jobs
by hongbo_zhang 3357 days ago
For web developers who are looking for an industrial strength functional language instead of JS, OCaml probably has the best story here.

Actually it has two OCaml->JS compilers of very high quality The first one, js_of_ocaml, could bootstrap the whole compiler several years ago(probably the first one there).

The recent one, https://github.com/bloomberg/bucklescript, push the JS compilation into next level, it generates fairly readable code, good FFI story, and its compilation is extremely fast, check out the compiler in JS version(http://bloomberg.github.io/bucklescript/js-demo/), and imagine how fast it would be for the compiler in native version. BuckleScript has a good story for Windows, and generates fairly efficient code, see benchmark here: https://github.com/neonsquare/bucklescript-benchmark BuckleScript is already used in production by big companies: for example Facebook messenger.com 25% is powered by BuckleScript, the new WebAssembly spec interpreter by Google is also partly cross compiled into JS by BuckleScript.

Disclaimer: I am one of the authors of BuckleScript

4 comments

I'm optimistic about Reason, Facebook's new syntax "skin" on top of OCaml. I find OCaml's syntax to be quite gnarly; of the MLs, F# is probably the cleanest and most modern-feeling. Something like F# without the .NET stuff could have been amazing.
I can confirm that the story of F# on the JS ecosystem is already quite good and is getting better every day. As already mentioned, Fable (http://fable.io) is the way to go today. I did two things that involve "writing compilers" using F# that target the web and did not have any notable issuues.

- My coeffects page (http://tomasp.net/coeffects) is an implementation of a simple ML-like language with coeffect type system. It was written using FunScript, which is a precursor of Fable - Fable improved many things, but this was over a year ago when it was not around yet.

- The Gamma (https://thegamma.net) is a web-based language for doing simple data science work and the compiler for that is written all in Fable. It works perfectly and integrates neatly with things like virtual-dom (source code is on GitHub https://github.com/the-gamma/thegamma-script)

Indeed, fable is a very neat project, but to be honest, it is not as mature as BuckleScript at this time.

For example, it takes around 20~80ms to compile a single file for BuckleScript, while Fable would talk 10x more to compile.

Its generated code is pretty but its performance is not very good, see this issue (https://github.com/fable-compiler/Fable/issues/646) "this can make a difference in speed of up to about six or seven times for tight loop code using tuples, records, lists, unions, etc.(compared with BuckleScript)"

But Fable is a nice project, JavaScript platform is large enough to have both :-)

I absolutely agree that the JS platform is large enough to have both!

That said, I think doing a fair comparison is going to be difficult. Although OCaml and F# share the same background, I think the OCaml and F# communities care about quite different things - and this can be seen in the difference between BuckleScript and Fable. OCaml compiler is very fast and produces efficient code and so it feels reasonable to expect the same for BuckleScript. F# is often slower, but people tend to care a lot about making interop nice. You can see this with the React bindings and Elmish tooling.

Those different goals are exactly the reason why there is room for both. I think Fable vs. BuckleScript mirror the philosophy of F# vs. OCaml with respect to .NET and native.

The good news is that you can have your cake and eat it too! Reason is a front-end to the OCaml compiler and BuckleScript is a back-end. Your Reason programs can be compiled to JS via BuckleScript. Yay!
Nice!
Fable: http://fable.io/

It's able to self-host as well. Check it out at http://fable.io/repl

F# also runs on .NET Core, which is cross-platform and comes with a good CLI. Documented, too: https://docs.microsoft.com/en-us/dotnet/articles/fsharp/tuto...

Fable looks great, and I might try it out, but I was thinking more along the lines of native, static compilation.
I find OCaml's syntax simple and clear. I don't get the reason for Reason, but hope it leads to more OCaml adoption.
OCaml might be simple and clear, but starting from Standard ML - there's a number of differences that feel like warts and needless complications for no discernable gain for the programmer.

I do think Reason fix up a few of these ancient and partially crumbled stone walls making the ocaml landscape easier to criss-cross for a new generation of programmers.

> there's a number of differences that feel like warts and needless complications for no discernable gain

Such as?

It's been a while - but pretty much what Reason address - although I'd prefer filling in SML for js-ish syntax.
I get the reason* for Reason even though it may ostensibly be a superficial one. There was a post by someone on HN saying they started using Reason and ended up using straight Ocaml.

* My earliest memories of attempting to use Ocaml was pasting something directly from a beginner's tutorial into ocamli and getting a baffling error message. I think it had to do with use of double semicolons vs single semicolons. Yet that wasn't mentioned in the entire tutorial.

Reason is more then a "slightly improved syntax to help attract programmers from mainstream languages".

It also improves error messages and tooling. It has something akin to JSX built into the lang.

>I find OCaml's syntax to be quite gnarly

What's wrong with the OCaml syntax? It's much more clean than say scala's one, it's indentation insensitive, and a' list feels more relevant than the list<'T>

It's a lot of little random things. For example, the ~keyword: syntax, the need to paranthesize where other languages don't (e.g.: "foo -1" doesn't work, you have to do "foo (-1)"). The way argumentless functions must be declared with "function". The expression termination issue (";;") is a lot less elegant than, say, Haskell's whitespace awareness. Operators not being overloaded is annoying, although there's a valid argument for explicitness.

Overall, it's not a terrible syntax, but it feels a lot like someone just invented things along the way as they needed them, without a cohesive plan. Lots of pragmatic but visually ugly choices.

I also take issue with the tooling; things like error messages, or just the antiquated feel of the CLI tools. For example, having a REPL without built-in readline support (rlwrap to the rescue) in this day and age is not acceptable.

>The way argumentless functions must be declared with "function".

Could you show an example, I don't get it?

>The expression termination issue (";;")

Strange, I've never used ";;" in my code, only in repl.

>Operators not being overloaded is annoying, although there's a valid argument for explicitness.

Overloading is harmful. It's definitely the wrong way to do ad-hoc polymorphism, and OCaml have a polymorphic comparison operators, which brought so much headache. Type classes or modular implicits are the right way to do ad-hoc. Looking forward to see modular implicits in OCaml [1].

>For example, having a REPL without built-in readline support (rlwrap to the rescue)

What do you mean by "readline" support?

[1] http://ocamllabs.io/doc/implicits.html

Sorry, I should have been clearer. As I'm aware you have the choice between several ways:

  let foo : unit -> unit = <code>

  let foo = function
    | <pattern match stuff>

  let foo = (function () -> <code>)

  let foo = (fun () -> <code>)
I'm not an expert, but I guess this awkwardness comes from OCaml not having a dedicated function-declaration syntax; so if you do:

  let foo = do_stuff + 42;
...then you're obviously just defining a variable, which is evaluated right away. Which means that the only way to define a "procedure"-type function that takes zero arguments is the above.

> What do you mean by "readline" support?

Readline is a library that adds a line editor to a REPL. It adds keyboard shortcuts (arrow keys etc.), history, autocompletion, and so on. Unlike almost every single REPL out there (Python, Ruby, Haskell, etc.), OCaml doesn't come with built-in support, as far as I've been able to determine. You have to run "rlwrap ocaml" to get Readline into your REPL.

>Readline is a library that adds a line editor to a REPL.

There is a great advanced REPL for OCaml if you need something beyond simple stuff:

https://github.com/diml/utop

You can also do this:

    let foo () = <code>
OCaml doesn't have argumentless functions.. But they do have functions that take a 'unit' argument.
I know, I've asked about this:

>The way argumentless functions must be declared with "function".

function is just a sugar for fun+match, what does it have to do with argumentlessness?

One problem is that it is full of shift-reduce conflicts, due to a lack of an "end" token in most expressions.

The one that bugs me the most is nested match expressions, which often need to be wrapped in parenthesis.

In OCaml's expression syntax, "begin" is a synonym for left parenthesis, and "end" is a synonym for right parenthesis. So I've taken to just using "begin match e with ... end" in every situation to avoid this problem.
F# has lots of .net warts. Haskell is probably the cleanest ML syntax-wise in somewhat widespread use.
And the OCaml-as-JS community is small and very welcoming. How often can you get first-class support from the compiler makers as a newbie? Hongbo Zhang and Jordan Walke and Cheng Lou are all on the Discord channel and are extremely helpful.

Jump in fellas, the language is powerful, and the community is nice!

I can testify that the the Discord channels are a very welcoming place.
I can also verify this. The documentation is not perfect, and the fine people who hang out on Discord were able to lead me on how to fix the docs, and get me up and running.

Also, having full Intellisense for a JavaScript like language is amazing! I found it better for Reason than Typesript, oddly enough even in VS Code.

I'd be interested to learn how web-dev in OCaml->JS compares to web-dev with Scala.js. The latter has the amazing JVM eco-system to hand.

(I'm not interested in a Scala vs Ocaml language comparison. I know both languages very well. I'd be interested in the quality of JS support.)

> The latter has the amazing JVM eco-system to hand.

What do you mean? Scala.js allows you to use things from the Java ecosystem in JavaScript?

Only if it's been ported to Scala.js; in fact, same goes for Scala to Scala.js, all libs need to be cross compiled.

The only thing you get for "free" in Scala.js is Scala, which is of course no small accomplishment, but the JVM ecosystem as a whole does not come with it.

That's what I thought, and why I was confused by the original comment. Scala.js doesn't seem to have any benefits over js_of_ocaml, unless you prefer the language itself.
I was expressing myself sloppily, sorry. You still can use many things in the JVM ecosystem because you can compile (most of) scala.js not only to Javascript but also to the JVM, and then analyse the code with JVM specific tools like fuzzers, debuggers, profilers etc. This is powerful. Making sure your code runs on two platform will expose additional problems that one platform alone doesn't do.
I see. Well, I suppose that's true of OCaml as well. Its ecosystem is smaller, but it does have some pretty powerful tools, including a time-traveling debugger.
better than clojure and f#?