
Why OCaml, why now? (2014) - lelf
https://spyder.wordpress.com/2014/03/16/why-ocaml-why-now/
======
jonsterling
Nice post! There are a lot of good reasons to use OCaml over Haskell which are
more compelling than “JavaScript”, though. A few of them are:

1\. modularity (and now that they have added generative functors à la SML, you
can have true abstraction)

2\. benign effects: in Haskell "proper", you do not have effects; rather you
have "codes" for effects, which get interpreted into effects by the RTS; this
rules out the possibility of, e.g., using effects to implement a semantically
pure interface. On the other hand, OCaml has _actual_ effects, which can be
used in an open-ended way to implement all sorts of functional interfaces.

3\. strictness: arguments abound about whether laziness or strictness is
better; for me, it comes down to the fact that with some pain, you can embed
laziness in a strict language with effects, but you cannot embed full-on ML-
style strictness into a language like Haskell; moreover, strictness-by-default
permits _safe_ uses of benign effects.

I'd call Haskell an expression-oriented programming language, since the types
end up classifying expressions and algorithms (i.e. the particular "effects"
you used get put into the type). Whereas I'd say (OCa)ML is a value-oriented
language, since values (canonical forms) are considered separately from
general expressions (canonical and non-canonical forms); moreover,
implementation details don't end up in the types, so you can really consider
them to be classifying values and functions (i.e. equivalence classes of
algorithms, not algorithms themselves). This is largely orthogonal from
strictness vs laziness, but as soon as you add partiality in, strictness
becomes the only tractable way to have canonical-form-based meaning
explanations for the judgements of the theory.

P.S. My day job is writing Haskell. (In case the Pedagogical Brethren wish to
come and "correct" me.)

~~~
jordwalke
I generally prefer programming with immutability, but I certainly appreciate
the ability to use "benign effects" in my programs. Besides the case for
performance, I have applied a strange combination of benign effects, GADTs,
and functors to generate a sort of "proof of type equality" between two values
passed into a framework, each of which are not known to the framework because
they're passed _into_ the framework by two separate clients of the framework.
At that point, I had the ability to reason about two values with arbitrary and
potentially distinct types, as either being not the same (None), or the same
Some(x, y) with x and y having the same type.

I have no clue if there's a more elegant way to do this (edit: there probably
is), but even I (as a n00b) was able to figure out how to do this by using
benign effects. There's only a single mutation in this library - but it was
such a critical one that made everything else possible.

I'm curious about the reason for preferring generative functors over
applicative functors. It seems like both could have valid use cases. Could you
point me to a writeup that explains why you believe generative functors are
superior?

~~~
jonsterling
After numerous discussions with Bob Harper (and reading Derek Dreyer's work,
who has been the biggest proponent for applicative functors), I have come to
understand that there are only two compelling use-cases for applicative
functors:

1\. higher order functors.

2\. modular type classes

Higher order functors are kind of cool, but IMO Standard ML does not seem to
be suffering too much from the lack of them. I'm not too interested in it,
since it gets super gnarly super fast, and this happens to be pretty much the
main use-case for applicative functors. I suspect that most use-cases of
higher order functors in OCaml could be reformulated to be first order, with a
lot less monkeying around in the module system. There may be compelling use-
cases though.

The other use-case is possibly a version of modular type classes that behaved
a bit more like Haskell's. The idea is that if functors are going to be
applied automatically during elaboration to provide something like type
classes, you'll get MkWelp(S) called in multiple places, and you would prefer
that any type members of the resulting structure be compatible. Applicative
functors would do this.

I am not too convinced by this use-case, though I could see that people would
find it useful.

In all other cases, generative functors have the correct semantics. Pretty
much the whole use-case of putting abstract types in a functor is that you can
then reason intensionally about them (i.e. distinguish them based on their
access path). This is super useful, for instance, if you have a notion of
"index" or something and you want to prevent yourself from using indexes from
one table in another one, or something along those lines.

This is what the Scala people mystifyingly call "path dependent types". It's
just generative abstraction.

So maybe it is an interesting feature to have applicative functors, but these
should be added post facto, and generative functors should be the default.
OCaml now supports generative functors if you add an extra () parameter; it's
strange syntax, but it's good enough for me! :)

~~~
jonsterling
lps25:

> Consider the case of a set implemented as a binary tree. The type of such a
> set should be parametrised by the type of the elements and the ordering
> used. With applicative functors this is the case as your set type will be
> `Set(O).t` where `O` is a structure containing the type and the ordering.
> With generative functors each individual set type is abstract -- so the type
> itself is not parameterised by the ordering.

You make a good point about this not being strictly about type classes. But
I'd say that the issue is only a problem in the presence of implicit
resolution, since otherwise, you can just bind the result of the functor to a
structure once and be done with it. It becomes an issue with type classes,
because you don't have the choice to share a single structure during
elaboration.

IMO, the generative version is still better for most use-cases (pure or not),
but it's nice that you can have both in OCaml.

~~~
jordwalke
>> since otherwise, you can just bind the result of the functor to a structure
once..

My understanding was that of lpw25's. I wanted to use applicative functors in
the same way type classes (or OCaml's modular implicits) would make use of
them, but even without type class's implicit resolution (explicitly specifying
them). I agree there isn't too much difference from doing the same with
generative functors, but the main difference is, as you said, I would need to
find a place (some appropriately accessible location in the namespace) by
which to access the result of these generative functor applications, and
that's just an extra point of friction (if I understand correctly). It's not
the end of the world as you said either way because we can do either.

Thanks for the help, jonsterling/lpw25.

------
didyoucheckthe
> The first question I usually get ... is “Why not Haskell?”.

> The answer is JavaScript.

My current favorite language for this is Elm[1]. It compiles to JS, is based
on Haskell, and has a few simple differences between either[2].

Elm doesn't let you use the tons of available Haskell libraries, and makes it
slightly painful to integrate with JS. But it's the coolest thing for the web
so far. And here's why:

It uses a completely declarative state machine to model a fully interactive
and complete GUI! This is the dream React.js and Om didn't even know they were
heading towards! And yes, it is as good as it sounds.

[1]: [http://elm-lang.org/](http://elm-lang.org/)

[2]: [http://elm-lang.org/learn/FAQ.elm](http://elm-lang.org/learn/FAQ.elm)

EDIT:

Also, Elm fixed Haskell's awful syntax record name collision problem, and
awesomely too!

~~~
jarcane
Purescript[1] is also gaining some traction and even has a pretty nice looking
book out. [2]

It has some changes however; most notably it's strictly evaluated rather than
lazy, and there are differences in how it handles type variables. [3]

Personally though, I've grown more fond of F# than Haskell; I only wish the
documentation for Websharper and Funscript was more solid.

[1] [http://www.purescript.org/](http://www.purescript.org/) [2]
[https://leanpub.com/purescript/read](https://leanpub.com/purescript/read) [3]
[https://github.com/purescript/purescript/wiki/Differences-
fr...](https://github.com/purescript/purescript/wiki/Differences-from-Haskell)

~~~
didyoucheckthe
Elm is actually 3 things rolled into one:

1\. an language very similar to Haskell

2\. a set of runtime libraries

3\. a technique for modeling a GUI as a declarative state machine

PureScript only competes with #1 and #2 here. Where Elm really shines is #3,
which #2 helps with a lot.

Technically #3 could be done in any language. But it really helps to model it
in such an expressive language with immutable data and no side-effects (except
via Signals).

~~~
purescript
I won't argue that Elm does anything other than an exemplary job at #3, but it
is worth noting that there are some interesting efforts to build similar
functionality in PureScript libraries:

[https://github.com/paf31/purescript-
thermite](https://github.com/paf31/purescript-thermite)

[https://github.com/kRITZCREEK/reactive-
psc](https://github.com/kRITZCREEK/reactive-psc)

[https://github.com/bodil/purescript-
signal](https://github.com/bodil/purescript-signal)

[https://github.com/michaelficarra/purescript-demo-
mario](https://github.com/michaelficarra/purescript-demo-mario)

[https://github.com/mechairoi/purescript-frp-
rabbit](https://github.com/mechairoi/purescript-frp-rabbit)

To me, this is the benefit of PureScript - yes, you have to do a little more
work, because you don't get these things for free from the compiler and tools,
but you gain complete control over your application structure. You're not
forced to work in some ambient Signal category.

------
dbpatterson
I think the author doesn't give enough credit to things that OCaml has that
Haskell doesn't have: a powerful module system (ie, functors), polymorphic
variants/subtyping, etc.

~~~
jordwalke
There's a bunch of other nice features of OCaml such as named arguments, fast
compile times, strictness, c-types, and reasonable records. To achieve (some
of the feature in) Elm style "structural subtyping" records in OCaml you use
the more verbose "object" keyword which is just a record with row
polymorphism. Most choose to stick with standard records because they compile
to more efficient code.

I think the ML module system (in OCaml and other languages) is very powerful
because it allows you to abstract and operate not only on types but also on
values simultaneously. F#, Haskell, and most others lack this but it would be
great if they were to officially adopt it. OCaml is also very easy to learn
and I seriously recommend Real World OCaml - it's free online and excellent.

~~~
tel
Total agreement about most of those things, but I want to indicate that
Haskell has some amount of row typing available via libraries like Vinyl and
it certainly has c-types.

~~~
carterschonwald
the most recent vinyl version (0.5)
[https://hackage.haskell.org/package/vinyl-0.5](https://hackage.haskell.org/package/vinyl-0.5)
winds up being a REALLY nice balance of flexibility, good type inference, and
a few other things.

Its actually simple enough that for a work project I decided it would be
simpler to write a custom version of the same datastructure just to avoid
extra deps. (and because I needed some slightly bespoke invariants)

~~~
jonsterling
:) Thanks! And yes, I don't know about Anthony, but my intention has always
been for Vinyl to be a proof-of-concept for what happens when you try to make
a clean, minimal & well-factored HList experience; my motto is, “Now build
your own Vinyl”.

------
ignoramous
Unless start-ups or top companies [0] start adopting OCaml, I doubt its rise
would be meteoric. Take go-lang, for example. It performs no better than Java
on JVM, but is gaining tremendous traction because Google is putting all its
weight behind it. I believe C# gets far less credit than it deserves... and
MSFT knows exactly what its doing by open sourcing it. I digress. I feel, one
is better off investing time in Clojure or Haskell (if functional programming
is what one is after), both of which are gaining a lot more traction in the
industry and the academia compared to OCaml.

I can speak from what I observed here at Amazon... which did try and make use
of Erlang (due to its excellent concurrency model) at one point, but gave up
(Simple DB is powered by Erlang, but its successor DynamoDB is JVM based). At
least Erlang had its chance... OCaml community within Amazon is non-existent.
Whereas Clojure (plenty of traction within due to STM on JVM, I guess) has
plenty going for it, as does Nodejs and go-lang. All of these plaforms are
popular due to the strong community presence both within the company and at
other tech power houses.

I'd also like to point out that the current crop of volunteers behind
ocaml.org [1] are doing a really great job of evangelising OCaml.

[0]
[https://ocaml.org/learn/companies.html](https://ocaml.org/learn/companies.html)
and [http://clojure.org/Companies](http://clojure.org/Companies) and
[https://wiki.haskell.org/Haskell_in_industry](https://wiki.haskell.org/Haskell_in_industry)

[1] [https://ocaml.org/about.html](https://ocaml.org/about.html)

~~~
danieldk
_Take go-lang, for example. It performs no better than Java on JVM, but is
gaining tremendous traction because Google is putting all its weight behind
it._

That's definitely a large factor. But let's not forget that Go already took
off when it was barely beyond being a 20% project. Go also fills some niches,
three particular ones I can think of are:

\- People who like Java, but favor the UNIX approach of small programs over
the JVM.

\- People who like Python or Ruby, but need more performance.

\- People who like C, but want garbage collection and some extra safety in
some of their projects.

Add to that that Go is trivial to learn for anyone with a Java, C, or C++
background. Of course, it takes some time to learn all the idioms, but someone
who knows languages with C-like syntax can start writing Go programs
productively within a day.

~~~
the_why_of_y
> People who like Java, but favor the UNIX approach of small programs over the
> JVM.

Ah, that must be why the golang toolchain does not support bloated enterprise
features like dynamic linking, so a hello world binary ends up almost 2MB. Go
UNIX!

------
tejinderss
Now that .net is going cross platform, I see a great future of f# (another
variant of ML family). Its got multi processors support too.

~~~
lmm
I think most people who wanted a cross-platform, VM-based, corporate-
ecosystem-integrated ML derivative with good concurrency support have already
found Scala :P.

~~~
aphexairlines
The problem with Scala is that you don't just get ML -- you have to accept
everything else that comes along -- so F# can be a more comfortable choice.

~~~
frowaway001
It might be easier to accept the additional parts of Scala, because the
creators didn't design them to be an tacked-on, intentionally horrible
feature. (OO in F#/OCaml anyone?)

Plus, sane typeclasses and higher-kinded types. :-)

~~~
sixbrx
I agree and I think F# would look a lot more attractive to functional
programmers if it had some type of polymorphism other than the C#-like
generics and traditional OO subtyping.

I can understand not choosing to go the ML route "down the Functor rat hole"
as one of its developers said. But then it also chooses not to do the simpler
type classes either. Apparently a proper impl would need CLR changes which is
a downside to the reified generics, they are baked in as C#/VB imagined them.
That leaves a language that conceptually is very close to C#/VB, with a
somewhat different syntax.

I find either of typeclasses or an ML-like module system far preferable for
_expressing_ abstractions than traditional ("left-biased") OO, even if OO can
(clumsily) get the same results in other ways.

Or I may have missed some developments in F# since I last looked. I really
hope so, F# does have a lot going for it.

------
yodsanklai
One thing I don't like about OCaml is that I always find myself writing the
same things, like "to_string" functions for my variant types (although there
must be some ways to alleviate this burden).

Also, when your programs use abstract data types you lose the benefits of
pattern matching. In that case, I'm happier with languages like Go or Ada with
a friendlier syntax.

~~~
tel
If you have an ADT but want pattern matching, try Scott Encoding.

For instance, here we have Option

    
    
        module Option = struct
          let scott (some : 'a -> 'r) 
                    (none : 'r) 
                    (opt  : 'a option) =
            match opt with
            | Some a -> some a
            | None   -> none
        end
    

For Option, since it's non-recursive, the Scott Encoding and the
recursor/inductor/Church Encoding are identical. Here's a linked list, though

    
    
        module LL : sig
          type 'a t
          val fold  : ('a -> 'r -> 'r) -> 'r -> ('a t -> 'r)
          val scott : ('a -> 'a t -> 'r) -> 'r -> ('a t -> 'r)
        end = struct      
          type 'a t = Cons of 'a * 'a t | Nil
          let rec fold cons nil = function
            | Cons (h, t) -> cons h (fold cons nil t)
            | Nil         -> nil
          let scott cons nil = function
            | Cons (h, t) -> cons h t
            | Nil         -> nil
        end
    

Anyway, the pattern should be more clear now. These provide effectively
"functionalized" pattern matching which you can apply whenever you need. In
particular, you can think of these as expressing a (potentially partial)
"view" of the abstract type. For instance, my linked list might have not been
a linked list exactly but instead some kind of tree, but `scott` and `fold`
let me expose a "view" of that tree as though it were a linked list.

~~~
ufo
If you look at this from an "expression problem" point of view, this version
with the records-of-functions is very similar to OO programming. But without
inheritance, classes and so on.

~~~
tel
I'm very much a fan of that POV. I think OO has a lot of mythology, but the
technology is relatively similar to something like OCaml or Haskell. Classes
are essentially just functions which return "structures".

Inheritance and open-recursion/dynamic binding are usually what remain. I'm
not terribly sure I miss them.

------
wyager
I honestly don't get how people can claim that Haskell is unusually hard to
learn. I started learning Haskell with zero functional programming experience,
and after getting over that initial pure+functional learning curve (which took
two or three weeks of casual learning), it was smooth sailing. Haskell is
actually a very simple language compared to popular languages like python or
C++; you just have to do a bit of thinking to get out of the
procedural/imperative/impure mindset.

I especially don't understand how people get tripped up by laziness. 99.9% of
strict code will work with no changes in a lazy environment. The rest usually
just needs a slight tweak to avoid memory leaks.

To anyone considering undertaking the modest effort required to learn Haskell,
I completely recommend it. My code in every language has tangibly improved.

~~~
paulrpotts
Keep in mind that writing something like this is not actually going to be
perceived as helpful to most people who may have difficulty with Haskell.
Consider a couple of possibilities.

First, you may be unusually quick, gifted, clever -- whatever you might want
to call it. In this case, the new concepts in functional programming might
come easy for you. That's great, but to people for whom they don't come so
easily, this could easily be considered discouraging, or else bragging.

Second, consider that maybe you haven't advanced as far in learning Haskell as
you think you have. In my estimation Haskell can take you up an abstraction
ramp, that has no clear and obvious "end." As a research language, higher up
that curve is some really mind-blowing stuff. So unless you're SPJ or beyond,
I wouldn't be quick to claim that Haskell isn't "unusually hard to learn."

Third, you may be a stage in your life where you can put a lot of free time
into learning, but recognize that not everyone is there. In my twenties, I
worked much more than full time, and in my spare time worked on yet more
programming, teaching myself other languages and environments. Really in
retrospect it's fortunate I didn't damage my physical or mental health more
than I did. But not everyone is in that boat now. In particular people who are
older and have "work/life balance," who are professionals in some form of
software development, may find that their employment doesn't offer them much
in the way of opportunities to learn another language, and the life part of
that work/life balance doesn't allow much time to do so.

Me, I'm somewhere partway up that ramp and proud of how far I've come (I feel
like I can use at least simple monads now) but still very aware that there is
a lot I don't fully grok (currently trying to get my mind around arrows). And
I agree, I completely recommend it, but just maybe don't be so glib to claim
it is not hard.

~~~
wyager
>Keep in mind that writing something like this is not actually going to be
perceived as helpful to most people who may have difficulty with Haskell

No, but hopefully it well help people who have yet to learn Haskell that not
everyone thinks it's particularly difficult. I'm not interested in convincing
the people who've tried and given up on it.

>That's great, but to people for whom they don't come so easily, this could
easily be considered discouraging, or else bragging.

So what do you propose? That I pretend it's really hard for me, even though
it's not? What effect do you think that's going to have?

>So unless you're SPJ or beyond, I wouldn't be quick to claim that Haskell
isn't "unusually hard to learn."

You don't have to be SPJ to learn Haskell (or talk about how hard it is). Do I
have to be Stroustrup to pass judgement on how hard it is to learn C++?

>In particular people who are older and have "work/life balance," ... and the
life part of that work/life balance doesn't allow much time to do so.

I obviously don't mean that Haskell is easy for every single person in the
world to learn; I mean that, as far as languages go, it's relatively easy
enough to learn. If I didn't have enough time to learn Haskell, I also
wouldn't have enough time to learn C++ or Python.

> but just maybe don't be so glib to claim it is not hard.

Again, what do you propose? Lie and tell people that it's super hard, so I
don't hurt their feelings if they can't figure it out?

~~~
bojo
Maybe consider a little humility first.

~~~
wyager
Does it demonstrate a lack of humility to be honest about how difficult
something was for me? I'm sorry my truthful assessment offends you. If
humility means pretending things are harder than they are, then I guess I
don't have any humility.

~~~
spyder81
Whether we find it offensive or not isn't relevant. Your comments are
degrading to those who find it difficult, and you are actively hostile when
they complain or we point this out.

Your attitude is one I see too often in the FP community, and well-meaning or
not it holds us all back.

~~~
wyager
>Your comments are degrading to those who find it difficult

Again, what do you propose I do about it? Should I never say anything positive
about anything, lest I offend someone who had a bad experience?

>Your attitude is one I see too often in the FP community

Which attitude is that? Optimism?

~~~
spyder81
> Should I never say anything

Well if you can't understand why your phrasing turns a positive idea into
making somebody feel bad, probably.

> Which attitude is that? Optimism?

A version of it, yes. The "if you don't find it easy you are the problem"
attitude.

------
andrewstuart
I wanted to like OCaml, mainly for working with Unikernels. When I looked at
the syntax it just looked very arcane, which was discouraging.

~~~
ignoramous
Might come handy in case you want help yourself get over the seemingly cryptic
syntax: [http://rigaux.org/language-study/syntax-across-
languages/](http://rigaux.org/language-study/syntax-across-languages/)

------
lmm
If it's about what's well-supported for compiling to Javascript, does scala.js
becoming non-experimental change the landscape?

~~~
spyder81
I knew about scala.js when writing the post (although it was still
experimental at the time) but I didn't mention it because I don't like Scala.
It looked promising when I first saw it, but then I had to write some
production code in it.

My opinion now is that if you're forced to use the JVM then Scala is one of
the best options. But that's a low bar, given the choice I would pick
something else.

------
saosebastiao
Is there anywhere that I can track the status of the multicore runtime and
modular implicits?

~~~
lpw25
Multicore:
[https://github.com/stedolan/ocaml](https://github.com/stedolan/ocaml)

Modular implicits: [https://github.com/ocamllabs/ocaml-modular-
implicits](https://github.com/ocamllabs/ocaml-modular-implicits)

