ReasonML Quick Start Guide
上QQ阅读APP看书,第一时间看更新

Exploring Reason

Ask yourself whether the following is a statement or an expression:

let foo = "bar";

In JavaScript, it's a statement, but in Reason, it's an expression. Another example of an expression is 4 + 3, which can also be represented as 4 + (2 + 1).

Many things in Reason are expressions, including control structures such as if-else, switch, for and while:

let message = if (true) {
"Hello"
} else {
"Goodbye"
};

We also have ternaries in Reason. Here is another way to express the preceding code:

let message = true ? "Hello" : "Goodbye";

Even anonymous block scopes are expressions that evaluate to the last line's expression:

let message = {
let part1 = "Hello";
let part2 = "World";
{j|$part1 $part2|j};
};
/* message evaluates to "Hello World" */
/* part1 and part2 are not accessible here */

A tuple is an immutable data structure that can hold different types of values and can be of any length:

let tuple = ("one", 2, "three");

Let's use what we know so far and dive right in with the FizzBuzz example from Reason's online playground. FizzBuzz was a popular interview question to determine whether a candidate is able to code. The challenge is to write a problem that prints the numbers from 1 to 100, but instead prints Fizz for multiples of three, Buzz for multiples of five, and FizzBuzz for multiples of both three and five:

/* Based on https://rosettacode.org/wiki/FizzBuzz#OCaml */
let fizzbuzz = (i) =>
switch (i mod 3, i mod 5) {
| (0, 0) => "FizzBuzz"
| (0, _) => "Fizz"
| (_, 0) => "Buzz"
| _ => string_of_int(i)
};

for (i in 1 to 100) {
Js.log(fizzbuzz(i))
};

Here, fizzbuzz is a function that accepts an integer and returns a string. An imperative for loop logs its output to the console.

In Reason, a function's last expression becomes the function's return value. The switch expression is the only fizzbuzz expression, so whatever that evaluates to becomes the output of fizzbuzz. Like JavaScript, the switch evaluates an expression and the first matched case gets its branch executed. In this case, the switch evaluates the tuple expression: (i mod 3, i mod 5).

Given i=1, (i mod 3, i mod 5) becomes (1, 1). Since (1, 1) isn't matched by (0, 0), (0, _), or (_, 0), in that order, the last case of _ (that is, anything) is matched, and "1" is returned. Similarly, fizzbuzz returns "2" when given i=2. When given i=3, "Fizz" is returned.

Alternatively, we could have implemented fizzbuzz using if-else:

let fizzbuzz = (i) =>
if (i mod 3 == 0 && i mod 5 == 0) {
"FizzBuzz"
} else if (i mod 3 == 0) {
"Fizz"
} else if (i mod 5 == 0) {
"Buzz"
} else {
string_of_int(i)
};

However, the switch version is much more readable. And as we'll see later in this chapter, the switch expression, also called pattern matching, is much more powerful than we've seen so far.