Cool Things Reason Formatter Does

Reason comes with a formatter that takes your badly written code and turns it into a well-indented piece of art:

Think of it as Prettier or Gofmt but for Reason.

Arguments about how to format code (and syntax in general) have plagued us since the dawn of programming; I’m not here to write about that. Instead, I’d like to show how refmt (“Reason format”) goes a step further and bakes in some of the wider-reaching semantic changes into the syntax itself, and why we do things this way.


  • We’ve built this JSX into the language-level.
  • It’s React-agnostic.

What does that have to do with syntax? Well, if you prettify your code by running refmt on the following:

MyComponent.createElement message::"hello" children::[] () [@JSX]

You’d get:

<MyComponent message="hello" />;

That’s a big syntax “formatting” refmt just did! So different that calling it formatting is almost a misnomer; but it’s indeed just a syntactic thing: those two lines are semantically equivalent. If you examine both abstract syntax trees, they’re identical. Get it?

For those of you who don’t use ReasonReact, that [@JSX] is just an attribute for hooking up macros. ReasonReact turns that agnostic createElement call into something React-specific. No standard, no extra tooling, no fuzz. Just one macro. We’ve pushed all this business from the meta-language level into the language itself.

If you’re not a fan of JSX, here’s a more mind-blowing example.

Function & Currying

The syntax sometimes shapes the semantics a whole lot. In Reason/OCaml, functions always take one, and only one, argument:

let increment = fun x => x + 1;

We simulate zero-argument function by passing an agreed-upon dummy argument called “unit”:

let logSomething = fun () => print_endline "hello!";
logSomething ();

() is syntax sugar for unit. We’ve now eliminated an edge-case (albeit often used) function calling convention while drastically simplifying the type system.

We simulate multi-arguments function call by giving a sugar to functions returning functions. This snippet:

let add = fun x => fun y => x + y;
let six = (add 5) 1;

refmt-ed, becomes:

let add = fun x y => x + y;
let six = add 5 1;

This is why you get currying for free:

let addTo5 = add 5; /* this simply returns `fun y => 5 + y */
let 6 = addTo5 1;

No complexity in the semantics nor the types. There was never any need to invent currying. We obtained multi-arguments functions by building up from a small block, rather than splitting up a big block and adding the mechanism of “currying” explicitly into a language.

Eh sure, but I can have it in my language too if I wrap the above with a nice syntax…

That’s not true for performance. The OCaml compiler (and BuckleScript) is able to “specialize” to the particular arity you’re using (proof here). So when it sees you call add 5 1, it’ll generate the code that actually applies a single function call with two arguments. Otherwise, you’d be naively allocating and calling n functions for a function of n arguments.

JS Objects

[%bs.obj {name: "Lil Reason", age: 10}];

This’ll compile down to a JS object of the same shape, fully typed. Forget for a moment how crazily great this is; here’s what it looks like when you refmt it:

{"name": "Lil Reason", "age": 10};

And now it even looks like a JS object! We’ve decided that the macro “bs.obj” (which, again, is agnostic and entirely customizable) was used enough to first-class it as a syntax feature.

What’s the point?

Try refmt-ing some code! Every time the code comes out looking slightly different, you might have learned a new (equivalent) idiom. Last example! Try formatting this:

switch foo {
| true => 1
| false => 2

What did you get? =)

Word of Caution

Have fun with Reason and see you in Discord!


I blog only when I have more important things to do

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store