Table of contents
Please support this book: buy it (PDF, EPUB, MOBI) or donate
(Ad, please don’t block.)

Basic values and types

In this chapter, we’ll look at ReasonML’s support for booleans, integers, floats, strings, characters and the unit type. We’ll also see a few operators in action.

To explore, we’ll use the interactive ReasonML command line rtop, which is part of the package reason-cli (the docs explain how to install it).

Interactions in rtop

Interactions in rtop look as follows.

# !true;
- : bool = false

Two observations:

ReasonML is statically typed – what does that mean?

Values in ReasonML are statically typed. What does static typing mean?

On one hand, we have the term type. In this context, type means “set of values”. For example bool is the name of the type of all boolean values: the (mathematical) set {false, true}.

On the other hand, we make the following distinction in the context of the life cycle of code:

Therefore static typing means: ReasonML knows the types of values at compile time. And types are also known while editing code, which supports intelligent editing features.

Get used to working with types

We have already encountered one benefit of static typing: editing support. It also helps with detecting some kinds of errors. And it often helps with documenting how code works (in a manner that is automatically checked for consistency).

In order to reap these benefits, you should get used to working with types. You get help in two ways:

No ad hoc polymorphism (yet)

Ad hoc polymorphism may sound brainy, but it has a simple definition and visible practical consequences for ReasonML. So bear with me.

ReasonML does not currently support ad hoc polymorphism where the same operation is implemented differently depending on the types of the parameters. Haskell, another functional programming language supports ad hoc polymorphism via type classes. ReasonML may eventually support it via the similar modular implicits.

ReasonML not supporting ad hoc polymorphism means that most operators such as + (int addition), +. (float addition) and ++ (string concatenation) only support a single type. Therefore, it is your responsibility to convert operands to proper types. On the plus side, ReasonML will warn you at compile time if you forget to do so. That’s a benefit of static typing.

Comments

Before we get into values and types, let’s learn comments.

ReasonML only has one way of writing comments:

/* This is a comment */

Conveniently, it is possible to nest this kind of comment (languages with C-style syntax are often not able to do that):

/* Outer /* inner comment */ comment */

Nesting is useful for commenting out pieces of code:

/*
foo(); /* foo */
bar(); /* bar */
*/

Booleans

Let’s type in a few boolean expressions:

# true;
- : bool = true
# false;
- : bool = false
# !true;
- : bool = false
# true || false;
- : bool = true
# true && false;
- : bool = false

Numbers

These are integer expressions:

# 2 + 1;
- : int = 3
# 7 - 3;
- : int = 4
# 2 * 3;
- : int = 6
# 5 / 3;
- : int = 1

Floating-point expressions look as follows:

# 2.0 +. 1.0;
- : float = 3.
# 2. +. 1.;
- : float = 3.
# 2.25 +. 1.25;
- : float = 3.5

# 7. -. 3.;
- : float = 4.
# 2. *. 3.;
- : float = 6.
# 5. /. 3.;
- : float = 1.66666666666666674

Strings

Normal string literals are delimited by double quotes:

# "abc";
- : string = "abc"
# String.length("ü");
- : int = 2

# "abc" ++ "def";
- : string = "abcdef"
# "There are " ++ string_of_int(11 + 5) ++ " books";
- : string = "There are 16 books"

# {| Multi-line
string literal
\ does not escape
|};
- : string = " Multi-line\nstring literal\n\\ does not escape\n"

ReasonML strings are encoded as UTF-8 and not compatible with JavaScript’s UTF-16 strings. ReasonML’s support for Unicode is also worse than JavaScript’s – already limited – one. As a short-term workaround, you can use BuckleScript’s JavaScript strings in ReasonML:

Js.log("äöü"); /* garbage */
Js.log({js|äöü|js}); /* äöü */

These strings are produced via multi-line string literals annotated with js, which are only treated specially by BuckleScript. In native ReasonML, you get normal strings.

Characters

Characters are delimited by single quotes. Only the first 7 bits of Unicode are supported (no umlauts etc.):

# 'x';
- : char = 'x'
# String.get("abc", 1);
- : char = 'b'
# "abc".[1];
- : char = 'b'

"x".[0] is syntactic sugar for String.get("x", 0).

The unit type

Sometimes, you need a value denoting “nothing”. ReasonML has the special value () for this purpose. () has its own type, unit and is the only element of that type:

# ();
- : unit = ()

In contrast to null in C-style languages, () is not an element of any other type.

Among other things, the type unit is used for functions with side effects that don’t return anything. For example:

# print_string;
- : (string) => unit = <fun>

The function print_string takes a string as an argument and prints that string. It has no real result.

Converting between basic types

ReasonML’s standard library has functions for converting between the basic types:

# string_of_int(123);
- : string = "123"
# string_of_bool(true);
- : string = "true"

All of the conversion functions are named as follows.

«outputType»_of_«inputType»

More operators

Comparison operators

The following are comparison operators. They are part of the few operators that work with several types (they are polymorphic).

# 3.0 < 4.0;
- : bool = true
# 3 < 4;
- : bool = true
# 3 <= 4;
- : bool = true

You cannot, however, mix operand types:

# 3.0 < 4;
Error: Expression has type int but expected type float

Equality operators

ReasonML has two equality operators.

Double equals (equality by value) compares values and does so even for reference types such as lists.

# [1,2,3] == [1,2,3];
- : bool = true

In contrast, triple equals (equality by reference) compares references:

# [1,2,3] === [1,2,3];
- : bool = false

== is the preferred equality operator (unless you really want to compare references).