Hacker News new | past | comments | ask | show | jobs | submit login
Functional Programming in OCaml (cornell.edu)
271 points by lelf 48 days ago | hide | past | web | favorite | 144 comments

Have you ever had one of those notepads with the kind of paper that made you want to write something, anything, even though you had nothing to write about? OCaml is just like that to me.

I stroll through the internet aimlessly and I find a page that mentions OCaml and my eyes light up; I see an .ml file and savor how it looks - functions written with great economy of expression, pattern matching through which data flows in well-defined pathways, abstract data types forming a network of rugged pipes and girders that makes invalid states impossible; and .mli files that presents modules like classic prose -- no hedges, contortions, or obscurities that undercut the reader's ability to understand the flow of data and the pathways through which it flows.

"Expression, carrying the elegance that comes from compressed energy, is like a perfectly tuned stringed instrument: the strings are taut to exact degrees to correspond to exact pitches that stand in exact relations to one another. The pitches and their relations exist before the strings are tuned. Each string is tuned to a pitch and the results are judged by comparison to this pre-existing reality. A musician tuning an instrument is not finished until everything is exactly right, but once it is exactly right, there is simply nothing left to do." -- Clear and Simple as the Truth: Writing Classic Prose, Thomas, Turner.

> Have you ever had one of those notepads with the kind of paper that made you want to write something, anything, even though you had nothing to write about?

That's exactly my experience with F# (not surprising, knowing how similar OCaml and F# are), but until I read your comment I didn't know how to explain this joy of reading and writing code in it.

I have a project that uses it, Meh. when people use Camlp4, it's a pain to read, the stuff is had to follow when it's a wall of text because of the level of indirection, Lwt makes everything hard.

When I was 20, I thought Ocaml was the best thing in the world, because I was writing it. Now, after years without using it, I have to maintain other people's code, my opinion changed.

I use ocaml daily for work - our core product is written in it. We actively avoid anything that deviates from the base language for reasons of clarity. No camlp4, no lwt, no fanciness other than some of the batteries libraries that improve on the std library. It does occasionally mean we type in more than we would if, say, we used extensions to give us Haskell-like do notation for monadic code, but at the end of the day we err on the side of being very conservative.

That's pretty much how we wrote the virt tools[1], basically we rely on the OCaml compiler, findlib, and not much else.

[1] https://github.com/libguestfs/libguestfs


I had not seen your project before and this looks exactly like the right hammer for a problem I needed to hit a week or so go.

Just wanted to point out that Camlp4 has been deprecated for a long time and replaced by the extension points mechanism.

Isn't PPX supposed to replace Camlp4?

I think so. See https://discuss.ocaml.org/t/is-camlp4-being-deprecated-in-fa...

I recently came back to OCaml (and js_of_ocaml) after being away for a few years. In the time I was gone, js_of_ocaml moved from camlp4 to ppx.

(edited to fix link)

It doesn't change the issue that when people have changed the grammar, you have to find their documentation to read their code, if the library is not used you have to read the parse tree transformation code, etc.

I see, your problem is the new grammar. I have never used OCaml with these features so I wasn't aware of this. Good to know.

The answer is not to use camlp4 or ppx, then, or at least limit it to a very very conservative level.

OCaml is the coolest language I’ve ever used. It’s the backbone of Harvard’s Intro to CS II, where they explain programming language paradigms with a heavy emphasis on the functional. OCaml’s expressiveness really shines through - I remember fondly how small yet powerful the language feels.

Unfortunately, I don’t know what to build with it... I’m the kind of person that builds projects for professional advancement, which curtails my creativity. I’ve thought of making a simple web server. Or maybe learning ReasonML. Any suggestions welcome.

OCaml really shines when your problem is data in, data out, and the transformation is non-trivial. So, maybe try compiling or generating stuff. I have two examples of my own: USSM¹, a simple static web site generator, and Monokex, a secure handshake generator like the Noise explorer (except much smaller, much simpler, and very incomplete).

[1]: http://loup-vaillant.fr/projects/ussm/

[2]: https://github.com/LoupVaillant/Monokex

>OCaml really shines when your problem is data in, data out, and the transformation is non-trivial.

So do you think it would be a good choice for creating a make-like tool, in which you want to support doing transitive / hierarchical makes, like target A depends on B, and B on C, so if C is newer than A, the tool should build B from C and then A from B, and other such variations?

Working on such an idea, currently in Python, and have an interest in and am reading about OCaml, hence asking. I think the work may involve a topological sort.

You should check out at least a couple of things:

- The Dune build system for OCaml, also written in OCaml, does exactly what you are describing: https://dune.build/

- Jane Street's Incremental library lets you build auto-updating computations which change whenever their inputs change: https://github.com/janestreet/incremental

Honourable mention: Thomas Leonard's really interesting series where he describes rewriting his dependency management tool, 0install, from Python to OCaml http://roscidus.com/blog/blog/2014/06/06/python-to-ocaml-ret...

Thanks for those links, will check them out. Took a quick look at Dune. Interesting that the simple examples I saw seem to use a Lisp-like syntax.

The Jane Street Incremental library idea sounds cool. I had thought of something very roughly like it, but for memory data, recently, in connection with that tool I'm working on.

Had come across Leonard's series of moving 0install from Python to OCaml earlier. Need to revisit it.

Yeah Dune uses s-expressions as its config format. It was born out of work done by Jane Street, and they like using s-exprs there.

Yes, that's the kind of thing I'd reach Ocaml for.

Great, thanks.

It scares me how much I relate to this but don’t have the eloquence to express it like you did.

I’ve evaluated it for a lot of smaller stuff I’ve needed to get done, but ultimately it just ends up being easier to use a framework or language that I already know.

Seriously, it is so good. I wish I could still program in OCaml professionally, as I did in the past.

Thanks for this (and the child comments). I was just about to post a “which functional language should I pick up” ask HN but I got most of my answer from this thread :D

I learned to program in Caml (20 years ago now... it still seems like yesterday) but switched to curly brackets land when I started working, and more recently Python. Last month I started reading Learn You a Haskell for Great Good and that made me nostalgic for FP. Haskell’s syntax and strict management of side effects is a bit of a turn-off though. The article and the comments have firmly put me in the Caml camp, but now I have to figure out which version (OCaml, F#, ReasonML) to go for.

Advice or opinions on the topic are welcome!

If you're writing anything for the browser, then I'll solidly recommend Reason. It works out of the box and ReasonReact is much more ergonomic compared to vanilla React + ImmutableJS + Redux + TypeScript combo. And there is a growing community around that use case in the Reason world.

If you want to write a command-line application, you can choose either OCaml or Reason, depending on your taste of syntax - both compile to native statically linked binaries. If you're doing anything related to compilers, OCaml is particularly suited for that, and you'll be in very good hands with Menhir (see: https://pl-rants.net/posts/case-for-new-lang/). Another systems software written in OCaml is unison (https://github.com/bcpierce00/unison), which is a file synchronization tool with a clear specification.

But if you want to write database backed web application servers in OCaml, with sessions, background jobs, admin interfaces, ORMs, database migrations and all that jazz, then you might want to give F# a go, or Haskell which has a better story around it. I do have a tiny Node server written in Reason that I use as an API endpoint but if I were to build a full-fledged system, there is nothing yet in the OCaml world like Rails or Django.

I used Unison for a decade, almost everyday, and it never failed. I never experienced this level of reliability with any other software. Perhaps all the credit goes to the programmer (Benjamin Pierce), not the language, but Unison certainly piqued my interest in Ocaml.

Thanks for the feedback. At this stage the goal is purely to dabble in FP with "Advent of Code" style mini-programs, and basically opening my developer chakras.

An added benefit would be to use this new language at work, which means that the size of the ecosystem (3rd-party modules, frameworks, etc.) can be a factor - one in which I guess OCaml is behind F# and Reason?

Note that OCaml and Reason are the same language with a different syntax. So when you're learning one, you're learning the other. There are some ecosystem differences because you can target native compilation, or JavaScript compilation. But otherwise the concepts carry over.

i personally highly recommend f#. it is one of the most practically designed langauges but still does functional and oop programming fantastically. some functional programming nerds complain it doesn’t have features like ocaml or sml’s modules or typeclasses like haskell, but it has other things that those languages don’t have. to my knowledge, it has feature parity with c# regarding oop with the exception of maybe a feature or two that doesn’t seem to affect things (i don’t know c#). meanwhile, it does functional programming very well.

it has nice error messages and clean syntax. it is easily installable on any platform. i took dan grossman’s programming language course on coursera. the first part of the course uses sml, and i simultaneously used sml, f#, racket, and scala to do the homework in. f# had the shortest solutions by far if counting lines of code.

a unique feature that i really like is its active patterns. f# already has amazing pattern matching, but you can define your own pattern matching with active patterns very easily. it is sort of close to defining your own pattern matching dsl.

in my opinion, it is criminally underused and under marketed by microsoft. in a world where python is taking over, f# is very refreshing.

Thanks, I'll have a look at F# syntax to see if it resonates. Is there a tutorial or (text)book you would recommend to get started?

> in a world where python is taking over, f# is very refreshing.

Can you elaborate? I happen to like Python but I'm always open for refreshments :D

the oft recommended f# for fun and profit is good as a reference, but i personally haven't found it good as a tutorial. the explanations are often not expedient and show (too) many ways of doing things to get to the point. i go there when i have something very specific in mind. i often find the official microsoft f# documentation to be quite good and my go to reference.

as for books, there are a lot. none of them really fully resonate with me, although they are usually pretty good, but the book functional programming using f# by hansen and rischel is fairly nice. it is more academic in tone, although it was written a while ago against an older version of f#, so there may be some slightly out of date or style code. the book expert f# is by the language designer, and it shows some nice advanced stuff in a clear way.

i also recommend going through the little mler by translating the sml code in the book to f#. it will get you used to using types and pattern matching the way they are done in ml dialects. you will be able to do everything up until they cover the module system.

i have some very simple code here: https://github.com/nikofeyn/ray-tracing-with-fsharp/tree/mas...

it isn't documented or to my usual style, as it is an incomplete project. i was going through the book ray tracing in one weekend by peter shirley and didn't finish. and this code was actually "ported" from racket code that i had originally started the book with. so it went from c++ -> racket -> f#. however, it shows some representative f# syntax for some numerical stuff. i have some more f# projects that show more type-based programming and pattern matching styles, but they are in private repositories.

i personally just do not like python. it feels very sloppily designed to me, and i prefer scheme-based languages like racket and ml-based languages like f#. i have only worked in python when work has compelled me to, and i hated every instance of it. a large majority of it is that python is just difficult to reason about and is sloppy. that and the ecosystem, while vast, is very sloppy. i have encountered countless dependency issues and version headaches with python. it just isn't fun. all the work to get something working in python is just not worth it and unless you are reliant on some particular library, i personally don't see a reason to use it.

meanwhile, racket and f# remain as easy to develop code as python, except that the code developed works and works well. they are just extremely nice languages to use. they are the only languages i have used where it doesn't seem they are fighting me.

if you use python's async code, check out f#'s async expressions. they are extremely easy to use.

i highly recommend dan grossman's programming languages course on coursera. the first module uses sml (you can basically directly port all the code and your own code to f# for fun and very easily). the second module uses racket. and the third module uses ruby. i recommend it for any programmer and especially for some not used to the functional style.

> Have you ever had one of those notepads with the kind of paper that made you want to write something, anything, even though you had nothing to write about?

Yup! The “official” notepads of my university are nice quality paper. They cost more but I enjoy them so much that I buy them anyhow.

Conversely, I’ve also had notepads with paper that felt so horrible to write on that I were unable to use them. Fortunately a friend of mine uses ink instead of mechanical pencil so for her using those notepads was not a problem so I gave them to her rather than having them sit in a closet or having to hand them over to recycling unused.

For me the absolute sweetspot is these


They are ridiculously cheap but the paper is lovely and they work fantastic with my ballpoints of choice.

I buy them 16 at a time.

They are probably nice but I think shipping them to Europe (where I live) would be very expensive probably :P

You can use this: https://reasonml.github.io/reason-react/

And you can interop between reason and Javascript!

Yep I know the feeling. I like Ocaml (and also Clojure) so much that it's one of the few languages were I'll actually don't really care about what I'm programming on as long as I get to use the language.

Building real things is great, but honestly for me one of the most satisfying things is just programming in an expressive and clean way for its own sake. It's great when you get a language or a tool that faciliates that.

If you have any web projects, you may be able to find a place for js_of_ocaml in one of them. I use it in a web app of mine. I started out writing the client-side scripting in plain JS (as opposed to React/Vue/etc.), but I am using js_of_ocaml lately to implement some more complex logic.

There’s also a new version of Real World OCaml under development:


Thanks for pointing this out. I read through bits of it last night.

From http://www.cs.cornell.edu/courses/cs3110/2019sp/textbook/int... :

> Milner received the Turing Award in 1991 in large part for his work on ML. The award citation includes this praise: "ML was way ahead of its time. It is built on clean and well-articulated mathematical ideas, teased apart so that they can be studied independently and relatively easily remixed and reused. ML has influenced many practical languages, including Java, Scala, and Microsoft's F#. Indeed, no serious language designer should ignore this example of good design."

What does 'award citation' mean in this context? Surely it can't mean the blurb around the original award back in '91.

It seems that award citation isn't exactly correct. See https://amturing.acm.org/award_winners/milner_1569367.cfm for where the blurb can be found.

It appears to be part of a biography that one can find for every Turing award winner. It's unclear when these blurbs were written or for what specific purpose.

OCaml 4.08 should be released quite soon with better error messaging, matter of month or two, I think. Too bad the expected GDB/DWARF integration didn't land in time. Hopefully next release...

Here's a Twitter thread listing some of the other upcoming improvements: https://twitter.com/etiennemillon/status/1095250528467079169

I like how, in this decade of Major Release every 6 monthes, OCaml still aggregates tiny version bumps slowly but surely :)

Does anybody think ReasonML will become more popular than plain OCaml outside of front end web development?


It is really puzzling to me, but I think this is true. I saw a comment on Reddit where someone said ReasonML had a pleasant syntax. I suppose if you have always dealt with C-style syntax, ReasonML might seem more familiar. However if you have tried a LISP or even Haskell/another ML family language, the syntax will probably seem like a major impediment to your productivity. However, having witnessed people moving to ReasonML from JavaScript, I have noticed that that initial familiarity makes a difference. Meanwhile LISP flavors languish because of their "alien" syntax.

It's not just the familiarity. ReasonML fixes real syntactic issues with OCaml:

- Having to learn how to use let ... in

- Having to learn how to use semi-colons and where and why

- Having to enclose `else` clauses in parentheses or begin/end keywords and learning why they are necessary

- Having to use multiple pairs of parentheses to enclose function arguments like `foo (a + b) (c - d)`. With Reason it's `foo(a + b, c - d)`. And another bonus, function application in Reason actually looks like high school math function application

- Having to learn to distinguish between tuples and multiple arguments in data constructors

Those are just off the top of my head. In addition, ReasonML's refmt tool lets you avoid bikeshedding discussions about code formatting–it's a whole-program formatter. And some additional syntax niceties like single-@-symbol annotations and the upcoming single-line comments (//)–something OCaml will most likely never get.

I wouldn't consider #1-3 to be issues with OCaml syntax. It took me a while to understand what was going on with them, but once I did, I had a solid understanding of expressions vs statements, which has helped me understand functional programming better in general. IMO blending the syntax for the two will make the earliest stages of learning easier but cause confusion and longer learning curves in the long run.

I can't see how. ReasonML syntax has a clear and uniform scope delimiter, curly braces. You are always sure which scope you're in, there's no room for ambiguity. You'll have to provide some more specific ways in which there could be confusion ;-)

Just because of FB support, or are there other reasons?

I think because of community interest and the need for a good general-purpose, efficient language. Here are some interesting community-developed projects:

- A cross-platform native-compiling GUI library with a React-influenced design: https://github.com/revery-ui/revery

- A lightning-fast Node version manager: https://github.com/Schniz/fnm

- Erlang-like multicore actors: https://github.com/ostera/reactor

That said, it's early days and the ecosystem has to (and will) mature a lot.

> the need for a good general-purpose, efficient language

Is the implication that plain OCaml is not good?

No, but realistically it's not very accessible (general-purpose). If people go for OCaml that's great, it's an amazing language and it's obviously the same language. But the ReasonML focus has been on developer experience and it's showing.

Can functional programming really be made more accessible by adding curly brackets? I came from C-style languages and now much prefer the syntax of Haskell and OCaml (although Haskell is my favourite). Learning the syntax was trivial compared to the paradigm and semantics.

Have you seen the Reason eco-system lately?

The esy package manager alone is a huge improvement over opam and npm.

Sorry, the developer experience in OCaml is almost unsurpassed. Nearly everything is perfect in that area, the only thing I miss are a couple of features (for example, native compiler support for all stdint.h exact width types).

Could there perhaps be some things that other mainstream developers need to do that you don't? Maybe, say, quickly scaffold a project with a CLI? With unit tests and a documentation pipeline out of the box? Access online documentation about packages in a centralized location? Easily sandbox library dependencies for multiple projects, while sharing as much as possible?

All that said, the OCaml tooling is definitely making strides in the right direction. Dune for one thing is incredible and we are lucky to have it. I'm just saying there is room to make things easier for developers, and Reason is also moving that forward.

I hope not. It is hideous and unnecessary.

I think the ReasonML parser and formatter have numerous issues that'll keep it from being adopted more widely.

Especially with nested expressions, the inability to find mismatched parens and braces ultimately turned my team's experiment with it sour.

The base language's grammar is said to have inconsistencies, but I think Reason's 1:1 matching while keeping older constructs makes translating very difficult. There is a tool to do so, but it's lossy.

That said, I use Reason React for a small front end project at work and sort of wish that the ppx for JSX wasn't tied to Reason, so that vanilla OCaml could be used instead.

An example of lossy translation from Reason -> OCaml:


You mean using ReasonReact without JSX in OCaml is a pain?

Doesn't it allow to quickly code something like HyperScript-Helpers?

I don't understand, what is being lost here?

`| ((Some (result))[@explicit_arity ]) -> Js.Array.forEach Js.log result`

the explicit_arity being added in. I can't think of other examples at the moment.

As far as I understand, 'lossy' would mean information was lost, right? But here it looks like information has been added.

I agree with that definition.

Maybe lossy is the wrong word, but the transforms historically had gotchas. PPX and what not. Especially when converting between Reason syntax version upgrades and the more stable OCaml syntax (locked to OCaml 4.2 because of bucklescript).

That doesn't necessarily mean lossy, but just that knowing what refmt will error out on depending on the version of Reason the code was written to target vs. locked down ML.

Interesting that the comments here are mostly around OCaml while the introduction states

> You might think this course is about OCaml. It's not.

> This course is about making you a better programmer.

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:


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

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!

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.

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.

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...

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

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.

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.

What is peoples experience with bucklescript and reasonML?

How are the platforms, libraries and future direction?

I am playing around with it. Right now I am trying to work my way through 99 problems [1], but using the ReasonML syntax [2]

I am quite far from using it professionally (or in anger, as they say), but my next toy-project/game will probably use ReasonML or ocaml.

ReasonML project tries to make most things work out of the box for particular purpose. It targets mostly frontend-devs and maybe node-js devs. I.e. I played around with buckle-script, and having it set-up on my machine was literaly just typing `npm i -g bs-platform` and adding reason-vscode extension to my visual studio code.

What I really like is the recent-is addition of esy.sh [3] that helps with compiling ReasonML trough ocaml to binary executables (previously mostly the buckle-script compilation to js worked out of the box)

Syntax is nicely familiar, type-error messages are approaching Elm-level of awesome a everything works, as long as you don't stray too much from the beaten path.

If you do stray, it can get awkward. Sometimes I didn't know if I should read documentation for reason, bucklescript or some other part of the underlying ocaml toolchain. Two examples:

First I played around with redoc [4] beautiful tool for generating documentation that contains embedded, compiled-to-js, executable code samples. But I could not compile my document, even though it looked like the example in the repo, I was getting an error about function not being present in a module.

After several hours I realize, that the example documentation was compiled with previous version of the tool, and that with lates instead just calling Module.f() I need to be calling PackageName.Module.f()

Second, I wanted to use esy.sh to work on those 99 problems. And I wanted to write tests for my solutions. I google around and find an ocaml unit-testing library [5] and it took me about an hour to figure out how to configure it. In the end it wasn't hard, it just took me quite some time to notice esy.sh is using dune [6] build system underneath and that I need to change the dune configuration files. I probably wouldn't need to do this for other libraries, but test-framework was using the ocaml extension-points (something like macro-system) and you needed to enable it in the build-config.

So far I still like it and it is not more complicated than dealing with other js-ecosystem frameworks :-) But going from node.js ecosystem to golang at work, I would preffer the go-style "just run this binary and you are fine" to js-ecosystem style "here is a rube-goldberg machine of build-systems".

[1] https://ocaml.org/learn/tutorials/99problems.html [2] https://reasonml.github.io/docs/en/overview [3] https://esy.sh/ [4] https://github.com/jaredly/redoc [5] https://github.com/janestreet/ppx_inline_test [6] https://dune.build/

TL;DR: I championed the addition of OCaml to write web apps in our team and had I had the decision now I would've just used TypeScript because of the much better tooling, better interop and pretty much as competent type system + less build step headaches.

We use BuckleScript (without Reason, plain OCaml) to deliver a few web apps meant to run on mobile. The experience is decent and the lack of multicore support for OCaml doesn't really matter when you execute in JavaScript.

OCaml is mostly a fine language, but anyone familiar with a more ergonomic language like PureScript will miss a ton of features (higher-kinded types, type classes, etc.. People usually like to say you can make up for it with functors, but it's not really the same at all; much more cumbersome and less ergonomic. We do use functors a lot, but to say they're doing the same thing is being a bit too liberal, IMO). There's been a plan to implement ad-hoc polymorphism for many years now and honestly I don't think it'll see the light of day. Most things in OCaml move at glacial speed and I think it's better to look elsewhere in languages that already have these features if you're not already invested.

BuckleScript obviously adds JS interop on top and with time I've come to resent how it's done. It's pretty verbose, doesn't fit in with the rest of the language and is generally speaking pretty fiddly. PureScript has much better interop that looks exactly like the rest of the language, no ugly decorators needed.

Over time I've come to realize that even though I may want to use PureScript for projects, it's probably not going to happen with the small community and higher degree of investment needed for people. So while PureScript is superior to pretty much all "write something that runs in the browser" solutions right now, we're not very likely to use it (yet). BuckleScript is mostly the same and on top of that it's based on a worse language moving slower, with an interop layer that's worse.

With that in mind, the sanest way to do it is just to use TypeScript. It rates better in almost every metric that has to do with "Is this usable for us?". It lacks the niceties like HKTs, etc., but can pretty easily make up for most other features. I realized this after working on a talk about designing programs via the type system and being able to do most things with TypeScript that I'd expect to have to use PureScript/OCaml for. There are still parts missing, but those parts are missing in OCaml too and PureScript is the only one that gets abstraction completely right on a language level, barring dependent types.

There's a way to simulate HKTs via type defunctionalization which is applicable to both OCaml and TypeScript, so you can approximate it, and there's a library for it out in the wild called `fp-ts`.

With TypeScript, the interop story is obviously as good as you're going to get. With strict mode turned on (it is by default) it's not going to allow nonsense and in the past few years it's gotten features that allow you to do tons of type system modelling. I've already made strides in our code base to support things that we're doing in OCaml and to a large extent it's mostly the same kind of feeling of "It compiles, so it's very likely actually correct".

So all in all, since I discovered how to express more interesting type concepts in TypeScript (I was previously convinced, mostly by FUD, that this wasn't (yet) possible) I'd rather we don't add any more OCaml projects as I think the tradeoffs just aren't the right ones anymore: OCaml's (possible) advantages in the type system are few and they don't at all make up for the barrier to learning (even though OCaml is a very simple language), worse tooling or worse interop.

Edit: I should also add we've had a ton of odd issues with building our OCaml code via BuckleScript. Rollup, for example, plain didn't work at all even though there's no logical reason it should be failing. One of the base/prim files was failing to build and no one on either side could figure out why. We currently run webpack without a custom bs loader and precompile the .ml files instead. Installing the `bs-platform` package in our docker containers with `yarn` also failed for unknown reasons, so for docker we also precompile the entire `bs-platform` from source.

> With TypeScript, the interop story is obviously as good as you're going to get.

I would just like to add, yes at the immediate level you can trivially use JavaScript code in TypeScript, but when you are within the TypeScript world there are a few issues:

- You need typings for the JavaScript libraries you're using, which are fortunately abundant but you have to keep an eye on their quality, as lots of things can be typed as `any` or `function` which is effectively saying 'whatever'.

- The process of getting typings is not as uniform as you'd expect. For example, you want to use the Web and related APIs? They are behind a compiler flag, not an import: https://www.typescriptlang.org/docs/handbook/compiler-option... . In BuckleScript all available third-party APIs are done uniformly with imports or hand-written typings.

- You want to write typings for a module? You'll need a `.d.ts` file to contain them. In BuckleScript, JavaScript typings and your OCaml/Reason code are uniformly contained in implementation/interface files. There's no distinction.

Regarding the bundling, it's hard to tell exactly what that was, but generally your strategy of explicitly splitting up the compilation steps is a good one.

Regarding the Docker issues, that is unfortunate, I wonder if you have tried one of the pre-built BuckleScript images? E.g. https://hub.docker.com/r/andreysenov/bs-platform

Thanks for the detailed answer :). You talked very nicely about the dev front - can I also ask how the Said languages fared at runtime?

I have no basis for talking about this. My suspicion is that our OCaml apps perform pretty terribly if you look at raw numbers, because we use what is essentially a hobbyist library called `bucklescript-tea`[0], which implements the Elm Architecture. I can only assume it's not optimized. Fortunately, we don't need it to be. The README stresses that it's fast, but meh.

From reading, the Reason team have had great success using react from Reason (so OCaml) even without manual optimizations, because of immutable data (even compared to immutable.js). Take that nugget with a pinch of salt, though, because I didn't hear it recently and I'm not sure I ever saw real numbers behind it.

0 - https://github.com/OvermindDL1/bucklescript-tea

It took a lot of clicks to get beyond the preamble and into the the substantive part:


I usually turn on colour filter and cannot find the click arrow initially. But those preamble seems okish for once. But good to have a shortcut.

Static functional ... lisp?

It often feel like a statically typed lisp with much less in the way of macros.

How does Ocaml compare to F# in expressing functional paradigm?

Here's a mail from Don Syme, F# creator, to the OCaml mailing list telling them how much influence they had on him and the entire .NET platform: http://caml.inria.fr/pub/ml-archives/caml-list/2006/11/d921c...

This was good to read!

"FWIW if you're interested I'd also like to mention the huge impact OCaml had on the design of .NET generics and C# 2.0, which I've never properly described on this list. It was seeing and experiencing polymorphic programming in OCaml and SML that made us persevere with the long and torturous process of convincing Microsoft that they should add such an "experimental and academic" feature as generics to their flagship runtime and languages. Of course we were in reality just making 1970s ideas work in practice, but at least now even Visual Basic has generics."

had no idea they resisted Generics.. I thought Java 5 was the main reason C# got them.

I think the one thing we can take away from the history of every mainstream language is they will all fight tooth-and-nail against generics because they are 'too complex', before coming up with some 'innovative approach to generics'.

I apologize for not being clear. Which one expresses functional paradigm more?

OCaml since it has functors.

F# is extremely similar. To put it in perspective how similar, I just ported a project for work over from F# to ocaml in a few days - mostly adding "in" for let blocks and parenthesizing nested match blocks where necessary, and replacing data structures with their ocaml equivalent. Large chunks of that code base didn't require any modification - I'd drop a 500 line source file in, run it through the ocaml compiler and have to deal with a handful of syntax tweaks to make it go through.

Which would you recommend from an ecosystem/performance perspective?

I’m thinking hard about picking up a new language and I think it’ll be oCaml, but F# does have the .net ecosystem behind it... how is ocaml’s stdlib? Is it easy to find what you need in 3rd-party modules?

F# for ecosystem. Most stuff you’d need is available via nuget. Plus, interop with C# is trivial, so all of that ecosystem is there too. Ocaml has opam for package finding, but it’s a bit sparser.

That said, I don’t tend to use a huge number of 3rd-party modules, so it’s not a big differentiator for me. Too much of a liability to have dependencies on some rando from the internet: for work, we tend to stick to modules from trusted sources in the rare chance we use them (eg, Jane street).

I apologize for not being clear. Which one expresses functional paradigm more?

From Wikipedia:

> F# is a member of the ML language family and originated as a .NET Framework implementation of a core of the programming language OCaml

So F# is based on OCaml and is very similar.

I apologize for not being clear. Which one is more expressive of functional paradigm?

F# uses a lot of OCaml syntax and is quite similar in many regards. Where they differ is F# is written on top of .NET, so users probably drop into the OO paradigm more often than they might in OCaml.

I apologize for not being clear. Which one expresses functional paradigm more?

I'm a novice in both, but my general impression is that they are so close in this regard as to not matter a whole lot as far as practical matters go. An expert can of course get detailed on the minutiae.

Put another way, OCaml only works on Windows via MinGW if I recall correctly. While that isn't a problem for most folks, I prefer to steer clear and only use a language on a platform with a significant number of users. Python is used extensively on Windows, Mac, Linux, ARM...etc, so I'll use it on any of those machines. I would guess nearly all OCaml use is done via Linux and next to zero on Windows, so I avoid it on Windows (not worth the effort). F# on the other hand has some support from Microsoft (not a ton, but enough) and a decent amount from the community with some neat innovations (at least I think they are) like type providers. It has full .NET interop when you need it.

Most of the syntax and method of using pattern matching everywhere is the same between them. The difference with F# that I find annoying is that I'm not super familiar with C#, so the times when you need to call .NET (Ex: iterating through a directory) directly, it is super obvious for someone with C# experience, but involves lots of digging through horrid Microsoft doc for me where only C# and VB.NET is covered 80% (I just made up that number, but F# is the least documented of the three official Lang's) of the time.

>OCaml only works on Windows via MinGW if I recall correctly.

Afaik OCaml could be built with MSVC. Lexifi use OCaml on windows only and even have a .NET layer


The lecture slides from previous semesters of the course linked from the book are also a great, and somewhat more conversational, resource for learning Ocaml.

Since there are a lot of questions regarding language choice for functional languages here, I think I'd be good to share my experience here.

I've learned from the ground up (since college) in a functional style through HtDP [1] and have used Racket (not just the teaching languages) and OCaml a good deal at this point. Some notes on my experiences with functional languages:


The Good:

- Incredibly powerful data matching/construction

- Typing gives good runtime guarantees

The Bad:

- The actual type checking messages from the compiler aren't very fun to wrangle with

- Parens being optional but then sometimes being needed for data constructions adds to confusion along with types

- There are a lot of other quirks that I only see occasionally but pull me out of ever thinking "this is the language I want to code in mainly". Things like being required to define mutually recursive functions in the same define clause, chained together with "and". The ambiguity of the need for semicolons, similar to parens. I won't detail them all here, but the quirks sum to something just large enough to be quite annoying to use.

Summary: It can be beautiful to work with until it snaps you right out of it. At this point I'm not thrilled to work in it, but I'm not mad either and will probably see the day I write more of it.


The Good:

- For me, the most readable. I'm not sure if this is a reflection of learning it first, but there's something so clean about it. While you can always drop into the more complex, the core basics read very well.

- Incredibly powerful macros. They are much more syntactically complex and resources for learning the ins and outs are hard to find, but once you get them, the world is your oyster.

The Bad:

For whatever reason, all of the practical packages you want simply don't exist yet, or if they do, break the cleanness bare Racket gives you in ways you probably shiver looking at. It's my only real negative, but the implication basically is that for any serious project, unless I want to write the tooling I want myself from the ground up, it's basically not an option.

What really sucks about this the most to me is that of all the languages, writing good libraries for Racket is the easiest given the powerful macro tooling. All the bare bones are there, they just need to be composed together ands abstracted the right amount while keeping the simplicity that makes Racket beautiful. When said aloud, it's a big ask. But IMO Python has done so well accomplishing this with things like requests, flask, etc - what's stopping Racket?

Oh, and the IDE (DrRacket), while deceptively powerful, still needs a competitor badly. I'd love to see a Jetbrains IDE for Racket, though of course I know that's not happening anytime soon.


I wish I could write everything in it, but the tooling and IDE just aren't there. Currently my focus is actually now on that tooling itself [2].

Functional languages I've looked at but have not written anything serious in:

Haskell: I get the appeal from a theory perspective, but the readability for me is absolutely terrible. Things are more verbose where they shouldn't be and too terse in the reverse. I haven't spent enough time to comment any further, but that alone was enough to steer me to explore other functional language options.

Clojure: The community seems great and I am excited it's gaining traction (and building out that tooling that Racket is sorely missing), but I wonder why these two have to be separated from each other. At the core of the language, it seems to me on cursory glance that clojure's syntax is just ever so slightly worse than Rackets, though less annoying than the quirks of OCaml. I can't help but wonder what would be if the clojure community instead wrote tooling for Racket (and some do!). For everyone involved closely with Clojure, I'd love to hear more about why it needed its own language. I know being on the JVM was big, but beyond that I'm pretty fuzzy.

Functional Programming in general:

While there are cases where imperative and object oriented programming make sense, I truly wish a day comes where the word mutation is taboo, imperative style is used sparingly when needed, and code readability and library design is valued above all else in industry. And there are good developments with things like Clojure, Redux, and the big languages embracing functional style more. Still, the difference of how I program in each style is truly incredible, and while my code is objectively better in the functional style, I currently rarely get to use it for projects, professional or personal.

To anyone who hasn't tried functional programming, I couldn't recommend it enough. HtDP or this book both seem like good places to start.

[1] https://www.htdp.org/2019-02-24/index.html

[2] In an attempt to improve the tooling to Racket itself, I am working on two libraries: A web framework and a basic ORM for structures. Both are in highly unstable condition at the moment so it is not recommended to try and contribute to them at this point, but I am targeting May to have stable 1.0 releases. hopefully expect to see a Show HN :) They are loosely inspired by Flask / SQLAlchemy, meant to address similar things in Racket. Links at [3] and [4]

[3] https://github.com/adjkant/web-sourcery

[4] https://github.com/adjkant/sql-sourcery

[5] Syntax Example for [3] and [4] together: https://github.com/adjkant/web-sourcery/blob/master/examples...

>Things like being required to define mutually recursive functions in the same define clause, chained together with "and".

This is not a quirk but a feature, just like rec keyword. It could be easily removed, but it's there for a reason, it makes code easy to reason about from the first glance.

I like the font of titles, can anyone advise what font it is?

Is there a PDF of this?

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