Supports OCaml monads

Functional language

There are good reasons why ReasonML uses the semantics of OCaml. The programming language has proven itself for over 20 years. Conveniently, JavaScript and OCaml have some things in common: Both languages ​​have both functional and object-oriented aspects, which makes it easier to adapt the syntax. In fact, some ReasonML code snippets look confusingly similar to JavaScript or Typescript code. The difference can only be clearly seen when special features of Reason are used.

The fact that there are some functional languages ​​in the JavaScript ecosystem raises the question of why developers shouldn't use Elm or PureScript instead of Reason, or why should Haskell transpile into JavaScript?

Two good reasons can be given as an answer: On the one hand, languages ​​like Haskell or PureScript are not exactly known for their flat learning curve. For example, Haskell does not allow direct side effects, so developers often fall back on monads that are reputed to be difficult to understand. This culminates in the legend of the so-called monad curse, which says: "The moment someone understands monads, the person loses the ability to explain monads".

Regardless of whether monads are really that complicated, the deterrent effect cannot be denied. ReasonML allows monads, but understanding the theory behind them is not required and they are not a typical part of the language or its documentation. For example, ReasonML allows side effects as normal and does not require pure functions like Haskell. In general, the ReasonML documentation tries to avoid too much theory and extreme jargon. Anyone who comes across zygohystomorphic prepromorphisms in the Haskell documentation may appreciate this.

The StringCalculator-Kata (programming exercise) by Roy Osherove should serve as a small example for functional programming and the combinability of functions.

The task is to add a string of comma-separated numbers like "1,2,3" to a sum - in this case to 6. The calculation should only take numbers smaller than 1000 into account. Therefore the following result would be correct:

stringCalc ("1,1005,2") => 3

The following imperative approach in classic JavaScript should serve as a comparison:

The disadvantage of the code is that the different aspects of the calculation are interlinked and the individual steps of the algorithm can only be identified with great difficulty.

Functional programming usually approaches the calculation with so-called pipelines:

In this code, every single step can be clearly seen and the individual aspects are neatly separated from one another. The first thing to do is to split the string using commas, then convert the individual strings into integer values ​​and only take numbers smaller than 1000 into account. At the end there is a totalization.

Now it is still a matter of programming the individual functions such as and.

Good teamwork

is a good example of the great interoperability with JavaScript. Developers can simply use the method for strings from the standard JavaScript library. ReasonML provides most of the standard JavaScript library under the module. A first implementation of looks like this:

let splitByComma = str => Js.String.split (",", str);

The syntax with the arrow function corresponds to that of the JavaScript versions from ES2015. For further processing, however, a list is more useful as a data structure than a JavaScript array. Therefore an additional conversion is necessary:

let splitByComma = str
=> Array.to_list (Js.String.split (",", str));

The legibility already suffers from the nesting and the many brackets. The pipe operator can help. It uses the result of a function call as the (last) argument of the next. Therefore the function can be written as follows:

let splitByComma = str
=> Js.String.split (",", str) |> Array.to_list;

or even as

let splitByComma = str
=> str |> Js.String.split (",") |> Array.to_list;

The code is easier to read: The function receives the string, splits it up and then converts the result array into a list. The reading direction runs from left to right without nesting, as it is the usual way of reading texts.

should convert the individual strings - in the example, and) into suitable values.

The functions and are required for this. The latter converts a single value, while the former applies the conversion to every single value in the list. This corresponds to the function that has been in JavaScript since ECMAScript5. A lot of values ​​go in and come out again after the transformation via the callback function, which is in the specific case.

let mapToInt = str => (int_of_string, str);

The transformation can be implemented even more easily in ReasonML: Since the language supports so-called auto currying, all functions can be partially executed. The call with only one argument would return in classic JavaScript because the second argument is missing. Instead, ReasonML returns a new, one-parameter function in which the argument is an integral part. This means that the complete function is already available, and you can directly link to the name:

let mapToInt = (int_of_string);

can be implemented with the classic filter function and a lambda:

let lessThan1000 = List.filter (x => x <= 1000);

Thanks to currying, it is not necessary to explicitly mention the list argument.

Finally, the sum function is still missing. can use the operator on a complete list - this corresponds to the method of a JavaScript array.

let sum = List.fold_left ((+), 0);

"folds" the list into a single value. ReasonML understands an operator in brackets as a function. This is a shorthand way of writing. Finally, the second argument is the starting value of the sum.

Incidentally, functional libraries such as Ramda or Lodash / FP achieve similarly good results in pure JavaScript. However, the direct language support in ReasonML for Auto Currying and the operator also increases readability. With a bit of luck, the pipe operator will also be available in JavaScript at some point. In the ECMSAScript specification it is currently on Stage 1. Since ReasonML has some planned JavaScript features, it is sometimes jokingly called "JavaScript2030".

Read comments (60) Go to homepage