ReasonML - Advent of Code - Day 1
Tags: reason, javascript, node, adventofcode
Published: 2019-12-01 17:47:31

---
title: ReasonML - Advent of Code - Day 1
series: Advent of Code with ReasonML
published: true
description: Attempting and describing Advent of code of solution in ReasonML
tags: reasonml, javascript, nodejs, adventOfCode
---

## Table Of Contents
* [Advent Of Code](#advent-of-code)
* [Intro to ReasonML](#intro)
* [Setup](#setup)
* [First Problem](#first-problem)
* [Second Problem](#second-problem)

### Advent Of Code <a name="advent-of-code"></a>

Advent of Code, is an advent calendar to solve small programming puzzles, every day for 25 days. once you solve one puzzle the next one opens up.

Signup for [Advent Of Code 2019](https://adventofcode.com/2019) if you haven't already, and please try and attempt it before reading this post, especially if you are a beginner. We are going to attempt it in [ReasonML](https://reasonml.github.io/)

### Intro to ReasonML <a name="intro"></a>

Reasonml is a typed language which compiles down to Javascript. To get more intro on it I would recommend you to visit the [official getting started guide](https://reasonml.github.io/docs/en/installation).

I am only going to introduce the language features which we are going to use and should be aware of.

- To define a variable we use the `let` keyword followed by the variable name.

```reasonml
let counter = 0;
```

- Types are inferred. This means that we don't have to write types for every variable we use. In the above example the variable `counter` is of type `int`.

- If a variable is of type `int` (integer) we cannot do any operations which needs a `float` (Floating number). To do any operation using that variable we will have to type cast (convert) it into another type, which is float in this example.

```reasonml
let floatingCounter = float_of_int(counter);
```

- Array is defined like so

```reasonml
let inputArray = [|1, 2, 3, 4|]
```

- Notice we use `|` after `[` and before `]`. This is to differentiate between array (similar to Javascript arrays) and List which is just `[1]`. We will focus on array for now.
- We define functions like so.

```reasonml
let myFunction = (param) => {
  // function body ...
  param
}
```

- Last statement of a function is the return value.
- If else statement is to be used for ternaries. By this I mean that the last statement in their block is the return value of the block, for example.

```reasonml
let initialValue = 10;
let counter =
  if (initialValue <= 10) {
    5;
  } else {
    10;
  };
```

- We don't need to import any files here. Files are automatically scoped as modules in ReasonML.
- Reasonml can be converted to Ocaml and Javascript. We use BuckleScript to convert ReasonML to Javascript, which provides us some handy utility functions from JS-land in Reason, like `Map`, `Reduce`, `Filter` etc. We will be using `Map` and `Reduce` from `Belt` which is a stdlib shipped with BuckleScript.
- To log using `console.log` we can use `Js.log`

### Setup <a name="setup"></a>

We want a bare minimum setup, in which we can create a file for each day and run it to get the solution. We will run the generated JS file in Node.

```bash
npm install -g bs-platform # to install buckle-script
bsb -init advent-of-code -theme basic-reason # initialise or project
cd advent-of-code
yarn add nodemon # nodemon helps us reload node server on file changes
```

We'll need a few scripts to get output on every change, add the following in you `package.json`.

```json
"scripts": {
    "nodemon": "nodemon ./src/index.bs.js",
    "build": "bsb -make-world",
    "start": "bsb -make-world -w",
    "clean": "bsb -clean-world"
  }
```

The files generated by BuckleScript has `.bs` before them and are readable like normal JS (they don't uglify it), we can edit them but I wouldn't recommend at this stage.

There are two scripts of interest here. `start` and `nodemon`. `start` will generate `.bs.js` files for us whenever we make change in `.re` (reasonml) files. `nodemon` will restart the `node` process whenever `index.bs.js` file changes or any of it's imported files change.

Rename the `Demo.re` file in src to `Day1.re` and create a function `main` in it, like so.

```reasonml
let main = () => {
  Js.log("Hello World")
}
```

Lets create our point of entry file, that is the `index.re` which will generate `index.bs.js`. Create the file in `src`.
We need to call our `main` function in `Day1.re` from `index.re`, in reasonml there is no need to import from other files, they are scoped with their file names so to call `main` function in `index.re` we can directly call it as `Day1.main()`. So our `index.re` file should look like.

```reasonml
Day1.main()
```

Now let's look at the first problem.

### First Problem <a name="first-problem"></a>

We are given a list of masses, and need to calculate the fuel needed for each one of them and report the total amount of fuel needed. Fuel needed for each item of mass `m` if given by `mass / 3 - 2`.

To solve the given problem, we will loop through each item in the list(array) calculate the fuel values, then add them to get the final result.

Let's define some test values in an array.

```reasonml
let test_values = [| 14, 9, 12 |]
```

Now we need a function to calculate the fuel for a given mass. This function will take an `int` divide it `3`, `floor` the result and subtract `2` from it.

```reasonml
let fuel_calculator = (mass) => {
  let mass_as_float = float_of_int(mass); // we need mass in float since floor accepts only floating values
  let mass_divided_by_three = mass_as_float /. 3.0; // notice the division sign and 3 as 3.0
  let floored_value = floor(mass_divided_by_three);
  let floored_value_as_int = int_of_float(floored_value)
  let fuel_value = floored_value_as_int - 2;
  fuel_value // the return value
}
```

Here we first convert the integer input to float, using `float_of_int` function. Then we divide by `3.0`, for denoting a value as float we have to add `.0` at the end. Then we floor the value using `floor` function, this is similar to `Math.floor` in JS. The floored value is a `float` and we want `int` to proceed, so we convert it to `int` using `in_of_floor`. Then we just subtract the value with `2`.

let's call the function to test if it works properly.

```reasonml
Js.log(fuel_calculator(14)) // should log '2'
```

let's refactor the function a bit.

```reasonml
let fuel_calculator = mass => {
  int_of_float(floor(float_of_int(mass) /. 3.0)) - 2;
};
```

We can use the `|>`(pipe) operator to pipe the value from one function to another. let's see how we can use it in the above function.

```reasonml
let fuel_calculator = mass => {
  ((mass |> float_of_int) /. 3.0 |> floor |> int_of_float) - 2;
};
```

You can read the above function as take mass and convert it to float, divide by 3, floor it, convert it back to int and subtract 2 from the result.

Now that we have a way to calculate the fuel, let's look into looping over the array. Just as in javascript we use `Array.map` to map over an array to get another array, we can use `Belt.Array` to loop over an array. _(I am assuming that you are aware of JS Map)_.

We can use it like below.

```reasonml
let mapping_function = (array_value) => array_value
let result = Belt.Array.map(input_array, mapping_function)
```

Since it would be tedious to write `Belt.Array` every time we use it, let's alias it.

```reasonml
module A = Belt.Array
let mapping_function = (array_value) => array_value
let result = A.map(input_array, mapping_function)
```

It would also be better if we can just pipe the array into Map like we did before. `|>` is used to pipe the last argument, and `->` is used to pipe the first argument.

```reasonml
module A = Belt.Array
let mapping_function = array_value => array_value;
let result = input_array->A.map(mapping_function);
```

Great, now we know how to map and we have the mapping function as well as the input, let's combine all of them together

```reasonml
module A = Belt.Array;

let fuel_calculator = mass => {
  ((mass |> float_of_int) /. 3.0 |> floor |> int_of_float) - 2;
};

let initialValue = [|14, 9, 12|];

let main = () => {
  let result = initialValue->A.map(fuel_calculator);
  result |> Js.log;
}
```

Console should log `[2, 1, 2]`.
Now we have an array of fuel values for each mass, we need to add all of them to get final result.

To do so we will use `Array.reduce`. and an add function. The add function takes 2 values `i` and `j` adds them and returns the value. _(I am asumming you know Array.reduce from JS)_

```reasonml
module A = Belt.Array;

let fuel_calculator = mass => {
  ((mass |> float_of_int) /. 3.0 |> floor |> int_of_float) - 2;
};

let initialValue = [|14, 9, 12|];

let add = (i, j) => i + j;

let main = () => {
  let result = initialValue->A.map(fuel_calculator)->A.reduce(add);
  result |> Js.log;
}
```

Console should log `5`. Now you can pass the input you get from Advent Of code to get your solution.

### Second Problem <a name="second-problem"></a>

Now we have to calculate the mass of the fuel we are adding, and the fuel required to add that fuel, and so on and so forth. This looks like a classic recursive call problem. let's see how we can approach it in ReasonML.

we first need to calculate the fuel required to carry the said mass, then we have to calculate the fuel required to carry that Fuel, and recursively call until the mass is 0.

```reasonml
let rec getTotalFuel = mass => {
  if (mass <= 0) {
    0;
  } else {
    let fuelReq = getFuel(mass);
    if (fuelReq <= 0) {
      mass;
    } else {
      getTotalFuel(fuelReq) + mass;
    };
  };
};
```

Notice we have added `rec` after let, to say that this function is a recursive function. Let's refactor it a bit, we can do away with just one if-else here. Since we know that any value less than 9 will mean fuel required is 0.

```reasonml
let rec get_total_fuel = mass => {
  if (mass < 9) {
    mass;
  } else {
    let fuelReq = getFuel(mass);
    get_total_fuel(fuelReq) + mass;
  };
};
```

The above function should give us our result, now we need to run it for each mass-fuel value.


```reasonml
module A = Belt.Array;

let fuel_calculator = mass => {
  ((mass |> float_of_int) /. 3.0 |> floor |> int_of_float) - 2;
};

let initialValue = [|14, 9, 12|];

let add = (i, j) => i + j;

let rec get_total_fuel = mass => {
  if (mass < 9) {
    mass;
  } else {
    let fuelReq = getFuel(mass);
    get_total_fuel(fuelReq) + mass;
  };
};

let main = () => {
  let result = initialValue->A.map(fuel_calculator)->A.map(get_total_fuel)->A.reduce(add);
  result |> Js.log;
}
```
Et voilà, we have our solution. We can refactor the above functions, like tail call optimisation etc.
We will explore more tomorrow. Mesage me or comment here if you have any question.

[Day 2 - Solution](https://dev.to/iamsolankiamit/reasonml-advent-of-code-day-2-5enk)