2019-03-28 Cristian Carlesso

I’ve recently stumbled upon a series of videos where Tsoding solves some brain teaser from Hacker Rank

but, you know, in

Haskell

In the first episode the problem was to get some integers as an input from the stdio and to sum them together.

This one line^{[1]} is the proposed solution:

```
main
= interact
$ show
. sum
. map read
. tail
. words
```

We know that *OCaml* is usually compared to *Haskell*, and that *Reason* is *basically just OCaml(TM)*.

Surely it would be easy to use imperative code to solve this problem, but can we reach something as close as possible to the solution above?

One thing that makes the expression above very readable is the chain of function compositions, unfortunately Reason doesn’t provide a `.`

operator, but luckily is super easy to define our own operators.

Unfortunately, we cannot use `.`

as it’s a reserved token, but we can though take inspiration from F#:

F# defines this two operators:

`>>`

Composes two functions (forward composition operator)

`<<`

Composes two functions but in reverse order: it executes the second one first (backward composition operator).

Let’s define the same operators in *ReasonML*:

First let’s define a *compose* function:

```
let compose
= (f, g, x) => g(f(x));
```

Let’s also define a *backwardsCompose* function that execute the second function first:

```
let backwardCompose
= (f, g, x) => f(g(x));
```

Now it’s possible to associate the two operators to these functions:

```
let (>>) = compose;
let (<<) = backwardCompose;
```

After this, let’s substitute *Haskell* `.`

for `<<`

and drop the `main =`

part as Reason doesn’t need it:

```
interact
$ show
<< sum
<< map read
<< tail
<< words
```

We’re unfortunately not done yet as those functions don’t exist in Reason, so we must define them ourself.

Let’s temporarily ignore `interact`

for a moment and try to define the remaining functions:

`show`

in*Haskell*converts from a number to a string, given that this problem is the sum of integers, we will use the standard`string_of_int`

:

```
let show = string_of_int;
```

`sum`

takes a list of numbers and return the sum; think of this as a`fold`

that apply the`+`

operator starting with`0`

as the initial value:

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

`map`

and`tail`

are the*Haskell*equivalents of respectively`List.map`

and the`List.tl`

functions:

```
let map = List.map;
let tail = List.tl;
```

`read`

is the reverse of`show`

: it takes a string and converts it to a number, so what we need here is`int_of_string`

:

```
let read = int_of_string;
```

- finally
`words`

split a string by white spaces, we can apply the`Str.split`

and`Str.regexp`

functions:

```
let words
= Str.split
@@ Str.regexp("[ \t\n]+");
```

Notice how here I’ve used the

`@@`

application operator:

`a @@ b`

is equivalent to`a(b)`

.This is the equivalent to

`$`

inHaskell, so we can either change the`$`

to`@@`

in the original expression or, since it’s not defined yet,tryto alias`$`

to`@@`

:

```
let ($) = @@;
```

We’re only left with `interact`

.

`interact`

puts all the standard input in a string; it then executes a function with it redirecting the output to the standard output.

I couldn’t find anything similar in *ReasonML*, so I hacked together the interact function using `read_line`

instead:

```
let interact
= f => {
let acc = ref([]);
try (
while (true) {
acc := List.concat(
[
acc^,
[read_line()]
]
);
}
) {
| End_of_file =>
String.concat("\n", acc^)
|> f
|> print_string
};
};
```

Ugh... this uses mutations and imperative code and handling with I/O.

Last thing remaining yet to do is to change the application of `map read`

as I’ve describe above in Reason function application is not the *space character*:

```
interact
$ show
<< sum
<< map(read)
<< tail
<< words
```

Rewriting this by reversing the functional composition gives us a more top-down flow:

```
interact
$ words
>> tail
>> map(read)
>> sum
>> show;
```

if we try to compile this, we’ll see that it doesn’t quite work as expected due of how *Reason* infer the associativity of `$`

and `>>`

, and it‘s solved by adding parenthesis:

```
interact
$ (
words
>> tail
>> map(read)
>> sum
>> show
);
```

The main reason `$`

exists in Haskell is because of associativity though.

Another way to avoid using parentheses we have in *Reason* is to use the *reverse application* operator `|>`

and moving `interact`

to the end:

```
words
>> tail
>> map(read)
>> sum
>> show
|> interact
```

Apart for the `interact`

function we reproduced a solution very similar to the *Haskell* one, while keeping the same level of purity using mostly a functional approach.

here I use indentation for people reading on a smartphone. ↩︎