
Functional Programming in OCaml - lelf
http://www.cs.cornell.edu/courses/cs3110/2019sp/textbook/
======
jasim
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.

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

~~~
StreamBright
Isn't PPX supposed to replace Camlp4?

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

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

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

[http://dev.realworldocaml.org/toc.html](http://dev.realworldocaml.org/toc.html)

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

------
yawaramin
From
[http://www.cs.cornell.edu/courses/cs3110/2019sp/textbook/int...](http://www.cs.cornell.edu/courses/cs3110/2019sp/textbook/intro/ocaml.html)
:

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

~~~
chillee
It seems that award citation isn't exactly correct. See
[https://amturing.acm.org/award_winners/milner_1569367.cfm](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.

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

~~~
badfrog
Here's a Twitter thread listing some of the other upcoming improvements:
[https://twitter.com/etiennemillon/status/1095250528467079169](https://twitter.com/etiennemillon/status/1095250528467079169)

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

~~~
yawaramin
Yes.

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

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

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

~~~
yawaramin
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 ;-)

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

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

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

~~~
fxfan
> 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?

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

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

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

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

[http://www.cs.cornell.edu/courses/cs3110/2019sp/textbook/bas...](http://www.cs.cornell.edu/courses/cs3110/2019sp/textbook/basics/interacting.html)

~~~
ngcc_hk
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?

~~~
yawaramin
[https://v1.realworldocaml.org/v1/en/html/the-compiler-
backen...](https://v1.realworldocaml.org/v1/en/html/the-compiler-backend-byte-
code-and-native-code.html#the-untyped-lambda-form)

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

~~~
yawaramin
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...](http://caml.inria.fr/pub/ml-archives/caml-
list/2006/11/d921ca59f12d434a3f005dfd07256d91.en.html)

~~~
jasim
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."

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

~~~
yawaramin
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'.

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

------
adjkant
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:

OCaml

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.

Racket

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.

Summary:

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](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](https://github.com/adjkant/web-
sourcery)

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

[5] Syntax Example for [3] and [4] together: [https://github.com/adjkant/web-
sourcery/blob/master/examples...](https://github.com/adjkant/web-
sourcery/blob/master/examples/0-0-1-example.rkt)

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

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

~~~
ericbb
I think it's "Play":
[https://fonts.google.com/specimen/Play](https://fonts.google.com/specimen/Play)

------
Shmebulock
Is there a PDF of this?

------
fxfan
What is peoples experience with bucklescript and reasonML?

How are the platforms, libraries and future direction?

~~~
59nadir
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.

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

~~~
59nadir
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](https://github.com/OvermindDL1/bucklescript-tea)

