One simple trick that will stop you swearing at Reason

Update:  it turns out that bucklescript actually spots this and reports it as a warning, but that warning can be hidden especially if you’re using create-react-app with reason-scripts.   It’s been proposed in the reason-scripts project here to switch this warning to an error to make it more obvious.

Learning Reason has been a great experience. But the one thing that has caught me out several times is partial function application.

As a quick reminder, one of the more powerful features of a functional programming language is how functions with multiple arguments work. When you use currying, a function with two arguments becomes a function with one argument that returns a function with one argument.

For a quick code example, we can have an add function that takes two arguments:

let add = fun x y => x + y;
add 1 2; /* 3 */

If this function is curried, we can partially apply the function by passing in one argument

let add1 = add 1;

add1 is a function that now expects one argument.

add1 4;  /*5*

If you’re new to functional programming, it’s easy to miss where you’ve not supplied enough arguments and instead have a partially applied function. Your code will compile and run but the function won’t get executed as it’s still waiting for another argument.

In particular for Reason, where you have labelled optional arguments, you have to append a positional (aka non-labeled) argument to the function call (conventionally ()) to tell the compiler you’ve finished applying. This caught me out when I changed how I was using a click event and the reduce function. Because an event handler (e.g. onChange or onClick is expecting a function, this works:

onClick=(self.reduce emailClick)

but if you handle the reduce elsewhere in a function, remember to apply it:

let handleClick _event => self.reduce emailClick;
...
onClick=handleChange

You can click all you like but the reduce will never get called.

Instead your code needs to look like this:

let handleClick _event => self.reduce emailClick ();

That final () finishes applying arguments to the function, and now works as you would expect.

Leave a Reply

Your email address will not be published. Required fields are marked *