Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
ReasonML Quick Start Guide
ReasonML Quick Start Guide

ReasonML Quick Start Guide: Build fast and type-safe React applications that leverage the JavaScript and OCaml ecosystems

Arrow left icon
Profile Icon Rafatpanah Profile Icon Joseph D'mello
Arrow right icon
$15.99 $22.99
eBook Feb 2019 180 pages 1st Edition
eBook
$15.99 $22.99
Paperback
$32.99
Subscription
Free Trial
Renews at $19.99p/m
Arrow left icon
Profile Icon Rafatpanah Profile Icon Joseph D'mello
Arrow right icon
$15.99 $22.99
eBook Feb 2019 180 pages 1st Edition
eBook
$15.99 $22.99
Paperback
$32.99
Subscription
Free Trial
Renews at $19.99p/m
eBook
$15.99 $22.99
Paperback
$32.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
OR
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Table of content icon View table of contents Preview book icon Preview Book

ReasonML Quick Start Guide

Introduction to ReasonML

The last decade has seen numerous paradigm shifts in the way we build user interfaces. Web applications have moved from server-side frameworks to client-side frameworks in order to provide better user experiences. Devices and browsers have become powerful enough to run robust client-side applications, and the JavaScript language itself has seen many improvements over the years. Progressive web apps provides a native-like user experience and WebAssembly allows for native-like performance on the web platform. An increasing number of applications are being built for the browser, resulting in larger client-side codebases needing to be maintained.

During this period, several frameworks, libraries, tools, and general best practices gained and then lost popularity, resulting in JavaScript fatigue for many developers. Companies are becoming increasingly cautious in committing to newer technologies due to their impact on hiring and retaining engineering talent, as well as productivity and maintainability. It can be an expensive mistake if you introduce the wrong technology (or the right technology at the wrong time) to your team.

For many companies and developers, React has proven to be a solid choice. In 2013, Facebook made the library open source after having used it internally since 2011. They challenged us to rethink best practices (https://www.youtube.com/watch?v=DgVS-zXgMTk&feature=youtu.be) and it has since taken over frontend development (https://medium.freecodecamp.org/yes-react-is-taking-over-front-end-development-the-question-is-why-40837af8ab76). Encapsulating markup, behavior, and style into reusable components has become a huge productivity and maintainability win. The abstraction of the DOM has allowed for components to be simple, declarative functions of its props that are easy to reason about, compose, and test.

Via React, Facebook has done an incredible job educating the frontend-developer community on traditional functional programming paradigms that make it easier to reason about and maintain code. And now, Facebook believes the time is right for ReasonML.

This is a two-year chart from npmtrends.com that shows the number of weekly npm downloads for some of the top JavaScript libraries and frameworks. ReactJS looks to be a clear winner and has reached over 2,500,000 downloads per week:

npmtrends.com

In this chapter, we'll do the following:

  • Discuss what ReasonML is and what problems it tries to solve
  • Understand some of the reasons why Facebook chose ReasonML as the future of ReactJS
  • Experiment with ReasonML in an online playground and examine its compiled (JavaScript) output

What is ReasonML?

Reason is a layer of syntax & tooling on top of OCaml, a language Facebook uses actively. Jordan [Walke] started the concept of Reason before React, in fact. We’re taking it and using it as an actual frontend language (among other uses) because we think that after three and half years, the React experiment has succeeded and people are now ready for Reason...

Let's expand on this quote. ReasonML is not a new language; it's a new syntax for the OCaml language that is meant to be familiar to JavaScript developers. Reason, as we'll call it from now on, has the exact same AST as OCaml, so Reason and OCaml only differ by syntax. The semantics are the same. By learning Reason, you're also learning OCaml. In fact, there's a command-line tool that converts between OCaml and Reason syntax, called refmt, which formats Reason/OCaml code similar to JavaScript's prettier—in fact, prettier was inspired by refmt.

OCaml is a general-purpose programming language with an emphasis on expressiveness and safety. It was initially released in 1996 and has an advanced type system that helps catch your mistakes without getting in the way. Like JavaScript, OCaml features garbage collection for automatic memory management and first-class functions that can be passed around as arguments to other functions.

Reason is also a toolchain that makes getting started easier for those coming from a JavaScript background. This toolchain allows us to take advantage of both the JavaScript and OCaml ecosystems. We will dive deeper here in Chapter 2, Setting Up a Development Environment. For now, we'll experiment directly in the online playground by visiting Reason's online playground at https://reasonml.github.io/try.

Try typing in this Hello World example into the online playground:

let message = "World";
Js.log("Hello " ++ message);

There are two things you'll notice:

  • The OCaml syntax is automatically generated in the lower-left section of the editor (not shown)
  • The Reason/OCaml code is compiled to JavaScript directly in the browser:
// Generated by BUCKLESCRIPT VERSION 3.2.0, PLEASE EDIT WITH CARE
'use strict';


var message = "World";

console.log("Hello World");

exports.message = message;
/* Not a pure module */

You may be wondering how the Reason/OCaml code is being compiled from within the browser. BuckleScript, Reason's partner project, compiles the OCaml AST to JavaScript. Since Reason and OCaml both get converted into the same OCaml AST, BuckleScript supports both Reason and OCaml. Furthermore, since BuckleScript is itself written in OCaml, it can be compiled to JavaScript and run directly in the browser.

Inspecting the compiled JavaScript reveals just how readable it is. Looking closer, you'll notice that the compiled output has also been optimized: within the console.log statement, the "Hello World" string has been inlined directly instead of using the message variable.

BuckleScript, using features of the OCaml type-system and compiler implementation is able to provide many optimizations during offline compilation, allowing the runtime code to be extremely fast.

Notably, BuckleScript also supports string interpolation (https://bucklescript.github.io/docs/en/common-data-types.html#interpolation):

/* The message variable is interpolated */
{j|Hello $message|j}

Why Reason?

What makes Reason so compelling? What can Reason do that TypeScript or Flow cannot? Is it just about having a static type-checker? These are some of the questions I had when first getting started with Reason.

Support for immutability and purity

Reason isn't just about having a static type system. Also important is the fact that Reason is immutable by default. Immutability is an important concept in functional programming. In practice, using immutable data structures (data structures that can't change) results in safer, easier-to-reason-about, and more maintainable code than their mutable counterparts. This will be a recurring theme throughout this book.

Purity is another important concept in functional programming. A function is said to be pure if its output is determined only by its input, without observable side-effects. In other words, a pure function doesn't do anything outside of returning a value. The following is an example of a pure function:

let add = (a, b) => a + b;

And, this is an example of an impure function:

let add = (a, b) => {
Js.log("side-effect");
a + b;
};

The side-effect in this case is writing to the browser's console. That's why, in our preceding Hello World example, BuckleScript included the /* Not a pure module */ comment at the end of the compiled output.

Mutating a global variable is also a side-effect. Consider the following JavaScript:

var globalObject = {total: 0};
const addAndMutate = (a, b) => globalObject.total = a + b;
addAndMutate(40, 2);
/* globalObject now is mutated */

The global object was mutated, and now its total property is 42. We now have to be aware of all areas where this globalObject is mutated whenever using it. Forgetting that this object is both global and mutable can lead to hard-to-debug problems. One idiomatic solution to this problem is to move globalObject into a module where it's no longer global. This way, only that module has access to it. However, we'd still need to be aware of all areas within this module that can update the object.

If globalObject was immutable instead, there would be no way to mutate it. Therefore, we wouldn't need an awareness of all the areas that can mutate globalObject, since there wouldn't be any of these areas. We'll see that, with Reason, it's fairly simple and natural to build real applications in this way by creating updated copies of the original data. Consider the following:

let foo = 42;
let foo = foo + 1;
Js.log(foo);
/* 43 */

The syntax feels quite natural. As we'll see later in this book, immutability—changing by returning updated copies instead of applying destructive changes in place—fits the React/Redux way of doing things quite well.

The original foo was not mutated; it was shadowed. Once shadowed, the old foo binding is unavailable. Bindings can be shadowed in local scopes as well as global scopes:

let foo = 42;

{
let foo = 43;
Js.log(foo); /* 43 */
};

Js.log(foo); /* 42 */

let foo = 43;
Js.log(foo); /* 43 */

Trying to mutate foo results in a compilation error:

let foo = 42;
foo = 43;
/* compilation error */

We can see that immutability and purity are related topics. Having a language that supports immutability allows you to program in a pure way without side-effects. However, what if there are times when purity would cause the code to become more complex and harder to reason about than using side-effects? You may be relieved to learn that Reason (interchangeable with OCaml throughout the rest of this book) is a pragmatic language that let's us cause side-effects when needed.

The key thing when using a language like [Reason] is not to avoid side-effects, because avoiding side-effects is equivalent to avoiding doing anything useful. It turns out, in reality, programs don't just compute things, they do things. They send messages and they write files and they do all sorts of stuff. The doing of things is automatically involving side-effects. The thing that a language which supports purity gives you, is it gives you the ability to, by and large, segment out the part that is side-effecting to clear and controlled areas of your code, and that makes it much easier to reason about.

It's also important to know that immutability doesn't come at the cost of performance. Under the hood, there are optimizations in place that keeps Reason's immutable data structures fast.

Module system

Reason has a sophisticated module system that allows for modular development and code organization. All modules are globally available in Reason, and module interfaces can be used to hide implementation details when needed. We will be exploring this concept in Chapter 5, Effective ML.

Type system

Reason's type system is sound, which means that, once compiled, there won't be runtime type errors. There is no null in the language, nor are there any bugs related to null. In JavaScript, when something is of the number type, it can also be null. Reason uses a special type for things that can also be null, and forces the developer to handle those cases appropriately by refusing to compile otherwise.

So far, we've already written some, albeit basic, Reason code without even talking about types. Reason infers types automatically. As we'll learn throughout this book, the type system is a tool that provides guarantees without getting in our way, and when used properly, can allow us to offload things to the compiler that we used to keep in our heads.

Reason's support for immutable programming, sound type system, and sophisticated module system are big parts of why Reason is so great, and there's something to be said about using all of these features together in one language that was built with these features in mind. When Facebook initially released React, they asked us to give it five minutes (https://signalvnoise.com/posts/3124-give-it-five-minutes) and, hopefully, that same frame of mind will pay off here as well.

Cross-platform

Building React applications with Reason is a lovely experience and, what's more, since OCaml is able to compile to native, we will be able to use these same skills to build apps that compile to assembly, iOS/Android, and much more. In fact, Jared Forsyth has already created a game called Gravitron (https://github.com/jaredly/gravitron) that compiles to iOS, Android, web, and macOS from one Reason codebase. That being said, the frontend JavaScript story is much more polished as of this writing.

Maintainability

Reason may take some time to get comfortable with, but you can think of this time as an investment in the maintenance and confidence of your future product. Although languages with gradual type systems, such as TypeScript, may be easier to get started with, they don't provide the sorts of guarantees that a sound type system such as Reason's can provide. Reason's true benefits cannot be completely conveyed within simple examples, and only really shine when they save you time and energy in reasoning about, refactoring, and maintaining your code. Put it this way; if someone told me they were 99% sure a spider wasn't in my bed, I would still have to check the entire bed because I don't like bugs!

As long as you're 100% in Reason and your code compiles, the type system guarantees there will be no runtime type errors. It's true that when you are interoperating with non-Reason code (JavaScript, for example), you introduce the possibility of runtime type errors. Reason's sound type system allows you to trust that the Reason parts of the application won't cause runtime type errors, which therefore allows you to focus extra attention on ensuring that these areas of the application are safe. In my experience, programming in a dynamic language can feel noticeably dangerous. Reason on the other hand feels like it always has your back.

Interoperability

That being said, sometimes—and especially when first learning about type systems—you may be unsure as to how to get your code to compile. Reason, through BuckleScript, allows you to drop down to raw JavaScript when you need to, either via bindings or directly inside your Reason (.re) files. This gives you the freedom to figure things out as you go along in JavaScript, and then once you're ready, convert that section of the code to type-safe Reason.

BuckleScript also lets us bind to idiomatic JavaScript in a very reasonable way. As you'll learn in Chapter 4, BuckleScript, Belt, and Interoperability, BuckleScript is an incredibly powerful part of Reason.

ES2030

Community

The Reason community is, hands down, one of the most helpful, supportive, and inclusive communities I've ever been a part of. If you have a question, or are stuck on something, the Reason Discord channel is the place to go for realtime support.

Reason Discord channel:

https://discord.gg/reasonml

Often, when starting with a new technology, talking to someone with experience for five minutes can save you hours of frustration. I've personally asked questions at all hours of the day (and night) and am so incredibly grateful for and amazed by how quickly someone helps me out. Take a moment to join the Discord channel, introduce yourself, ask questions, and share your feedback on how to make Reason better!

The Future of ReactJS

In practice, few real-world applications use just ReactJS. Additional technologies, such as Babel, ESLint, Redux, Flow/TypeScript, and Immutable.js, are typically brought in to help increase the maintainability of a codebase. Reason replaces the need for these additional technologies with its core language features.

ReasonReact is a Reason library that binds to ReactJS and provides a simpler, safer way to build ReactJS components. Just like ReactJS is just JavaScript, ReasonReact is just Reason. Additionally, it's easy to incrementally adopt because it was made by the same person who created ReactJS.

ReasonReact comes with a built in router, Redux-like data management, and JSX. You'll feel quite at home coming from a ReactJS background.

It's important to mention that Reason/ReasonReact is already being used by several companies in production, including within one of the largest codebases in the world. Facebook's messenger.com codebase is already over 50% converted to ReasonReact.

Every ReasonReact feature has been extensively tested on the messenger.com codebase.

As a result, new releases of Reason and ReasonReact come with code mods that automate much, if not all, of the upgrade process for your code base. New features are thoroughly tested internally at Facebook before they're released to the public, and this results in a pleasant developer experience.

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.

Data structures and types

A type is a set of values. More concretely, 42 has the int type because it's a value that's contained in the set of integers. A float is a number that includes a decimal point, that is, 42. and 42.0. In Reason, integers and floating point numbers have separate operators:

/* + for ints */
40 + 2;

/* +. for floats */
40. +. 2.;

The same is true for -., -, *., *, /., and /.

Reason uses double quotes for the string type and single quotes for the char type.

Creating our own types

We can also create our types:

type person = (string, int);

/* or */

type name = string;
type age = int;
type person = (name, age);

Here's how we create a person of the person type:

let person = ("Zoe", 3);

We can also annotate any expression with its type:

let name = ("Zoe" : string);
let person = ((name, 3) : person);

Pattern matching

We can use pattern matching on our person:

switch (person) {
| ("Zoe", age) => {j|Zoe, $age years old|j}
| _ => "another person"
};

Let's use a record instead of a tuple for our person. Records are similar JavaScript objects except they're much lighter and are immutable by default:

type person = {
age: int,
name: string
};

let person = {
name: "Zoe",
age: 3
};

We can use pattern matching on records too:

switch (person) {
| {name: "Zoe", age} => {j|Zoe, $age years old|j}
| _ => "another person"
};

Like JavaScript, {name: "Zoe", age: age} can be represented as {name: "Zoe", age}.

We can create a new record from an existing one using the spread ( ... ) operator:

let person = {...person, age: person.age + 1};

Records require type definitions before they can be used. Otherwise, the compiler will error with something like the following:

The record field name can't be found.

A record must be the same shape as its type. Therefore, we cannot add arbitrary fields to our person record:

let person = {...person, favoriteFood: "broccoli"};

/*
We've found a bug for you! This record expression is expected to have type person The field favoriteFood does not belong to type person
*/

Tuples and records are examples of product types. In our recent examples, our person type required both an int and an age. Almost all of JavaScript's data structures are product types; one exception is the boolean type, which is either true or false.

Reason's variant type, which is an example of a sum type, allows us to express this or that. We can define the boolean type as a variant:

type bool =
| True
| False;

We can have as many constructors as we need:

type decision =
| Yes
| No
| Maybe;

Yes, No, and Maybe are called constructors because we can use them to construct values. They're also commonly called tags. Because these tags can construct values, variants are both a type and a data structure:

let decision = Yes;

And, of course, we can pattern match on decision:

switch (decision) {
| Yes => "Let's go."
| No => "I'm staying here."
| Maybe => "Convince me."
};

If we were to forget to handle a case, the compiler would warn us:

switch (decision) {
| Yes => "Let's go."
| No => "I'm staying here."
};

/*
Warning number 8 You forgot to handle a possible value here, for example: Maybe
*/

As we'll learn in Chapter 2, Setting Up a Development Environment, the compiler can be configured to turn this warning into an error. Let's see one way to help make our code more resilient to future refactors by taking advantage of these exhaustiveness checks.

Take the following example where we are tasked with calculating the price of a concert venue's seat given its section. Floor seats are $55, while all other seats are $45:

type seat =
| Floor
| Mezzanine
| Balcony;

let getSeatPrice = (seat) =>
switch(seat) {
| Floor => 55
| _ => 45
};

If, later, the concert venue allows the sale of seats in the orchestra pit area for $65, we would first add another constructor to seat:

type seat =
| Pit
| Floor
| Mezzanine
| Balcony;

However, due to the usage of the catch-all _ case, our compiler doesn't complain after this change. It would be much better if it did since that would help us during our refactoring process. Stepping through compiler messages after changing type definitions is how Reason (and the ML family of languages in general) makes refactoring and extending code a safer, more pleasant process. This is, of course, not limited to variant types. Adding another field to our person type would also result in the same process of stepping through compiler messages.

Instead, we should reserve using _ for an infinite number of cases (such as our fizzbuzz example). We can refactor getSeatPrice to use explicit cases instead:

let getSeatPrice = (seat) =>
switch(seat) {
| Floor => 55
| Mezzanine | Balcony => 45
};

Here, we welcome the compiler nicely informing us of our unhandled case and then add it:

let getSeatPrice = (seat) =>
switch(seat) {
| Pit => 65
| Floor => 55
| Mezzanine | Balcony => 45
};

Let's now imagine that each seat, even ones in the same section (that is, ones that have the same tag) can have different prices. Well, Reason variants can also hold data:

type seat =
| Pit(int)
| Floor(int)
| Mezzanine(int)
| Balcony(int);

let seat = Floor(57);

And we can access this data with pattern matching:

let getSeatPrice = (seat) =>
switch (seat) {
| Pit(price)
| Floor(price)
| Mezzanine(price)
| Balcony(price) => price
};

Variants are not just limited to one piece of data. Let's imagine that we want our seat type to store its price as well as whether it's still available. If it's not available, it should store the ticket holder's information:

type person = {
age: int,
name: string,
};

type seat =
| Pit(int, option(person))
| Floor(int, option(person))
| Mezzanine(int, option(person))
| Balcony(int, option(person));

Before explaining what the option type is, let's have a look at its implementation:

type option('a)
| None
| Some('a);

The 'a in the preceding code is called a type variable. Type variables always start with a '. This type definition uses a type variable so that it could work for any type. If it didn't, we would need to create a personOption type that would only work for the person type:

type personOption(person)
| None
| Some(person);

What if we wanted an option for another type as well? Instead of repeating this type declaration over and over, we declare a polymorphic type. A polymorphic type is a type that includes a type variable. The 'a (pronounced alpha) type variable will be swapped with person in our example. Since this type definition is so common, it's included in Reason's standard library, so there's no need to declare the option type in your code.

Jumping back to our seat example, we store its price as an int and its holder as an option(person). If there's no holder, it's still available. We could have an isAvailable function that would take a seat and return a bool:

let isAvailable = (seat) =>
switch (seat) {
| Pit(_, None)
| Floor(_, None)
| Mezzanine(_, None)
| Balcony(_, None) => true
| _ => false
};

Let's take a step back and look at the implementations of getSeatPrice and isAvailable. It's a shame that both functions need to be aware of the different constructors when they don't have anything to do with the price or availability of the seat. Taking another look at our seat type, we see that (int, option(person)) is repeated for each constructor. Also, there isn't really a nice way to avoid using the _ case in isAvailable. These are all signs that another type definition might serve our needs better. Let's remove the arguments from the seat type and rename it section. We'll declare a new record type, called seat, with fields for section, price, and person:

type person = {
age: int,
name: string,
};

type section =
| Pit
| Floor
| Mezzanine
| Balcony;

type seat = {
section, /* same as section: section, */
price: int,
person: option(person)
};

let getSeatPrice = seat => seat.price;

let isAvailable = seat =>
switch (seat.person) {
| None => true
| Some(_person) => false
};

Now, our getSeatPrice and isAvailable functions have a higher signal-to-noise ratio, and don't need to change when the section type changes.

As a side note, _ is used to prefix a variable to prevent the compiler from warning us about the variable being unused.

Making Invalid States Impossible

Let's say that we'd like to add a field to seat to hold the date a seat was purchased:

type seat = {
section,
price: int,
person: option(person),
dateSold: option(string)
};

Now, we've introduced the possibility of an invalid state in our code. Here's an example of such a state:

let seat = {
section: Pit,
price: 42,
person: None,
dateSold: Some("2018-07-16")
};

In theory, the dateSold field should only hold a date when the person field holds a ticket holder. The ticket has a sold date, but no owner. We could look through our imaginary implementation to verify that this state would never happen, but there would still be the possibility that we missed something, or that some minor refactor introduced a bug that was overlooked.

Since we now have the power of Reason's type system at our disposal, let's offload this work to the compiler. We are going to use the type system to enforce invariants in our code. If our code breaks these rules, it won't compile.

One giveaway that this invalid state could exist is the use of option types within our record field. In these cases, there may be a way to use a variant instead such that each constructor only holds the relevant data. In our case, our sold-date and ticket-holder data should only exist when the seat has been sold:

type person = {
age: int,
name: string,
};

type date = string;

type section =
| Pit
| Floor
| Mezzanine
| Balcony;

type status =
| Available
| Sold(date, person);

type seat = {
section,
price: int,
status
};

let getSeatPrice = (seat) => seat.price;

let isAvailable = (seat) =>
switch (seat.status) {
| Available => true
| Sold(_) => false
};

Check out our new status type. The Available constructor holds no data, and Sold holds the sold date as well as the ticket holder.

With this seat type, there's no way to represent the previous invalid state of having a sold date without a ticket holder. It's also a good sign that our seat type no longer includes option types.

Summary

In this chapter, we got a feel for what Reason is and what problems it tries to solve. We saw how Reason's type inference removes much of the burden associated with statically-typed languages. We learned that the type system is a tool that can be used to provide codebases with powerful guarantees that provide an excellent developer experience. While Reason may take some time to get used to, it's well worth the investment for medium-sized to larger codebases.

In the next chapter, we'll learn about Reason's toolchain when we set up our development environment. In Chapter 3, Creating ReasonReact Components, we'll start to build an application that we'll use throughout the rest of this book. By the end of this book, you'll be comfortable building real-world React applications in Reason.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Hands on learning by building a real world app shell that includes client-side routing and more.
  • Understand Reason’s ecosystem including BuckleScript and various npm workflows.
  • Learn how Reason differs from TypeScript and Flow, and how to use it to make refactoring less stressful.

Description

ReasonML, also known as Reason, is a new syntax and toolchain for OCaml that was created by Facebook and is meant to be approachable for web developers. Although OCaml has several resources, most of them are from the perspective of systems development. This book, alternatively, explores Reason from the perspective of web development. You'll learn how to use Reason to build safer, simpler React applications and why you would want to do so. Reason supports immutability by default, which works quite well in the context of React. In learning Reason, you will also learn about its ecosystem – BuckleScript, JavaScript interoperability, and various npm workflows. We learn by building a real-world app shell, including a client-side router with page transitions, that we can customize for any Reason project. You'll learn how to leverage OCaml's excellent type system to enforce guarantees about business logic, as well as preventing runtime type errors.You'll also see how the type system can help offload concerns that we once had to keep in our heads. We'll explore using CSS-in-Reason, how to use external JSON in Reason, and how to unit-test critical business logic. By the end of the book, you'll understand why Reason is exploding in popularity and will have a solid foundation on which to continue your journey with Reason.

Who is this book for?

The target audience of this book is web developers who are somewhat familiar with ReactJS and who want to learn why ReasonML is the future of ReactJS.

What you will learn

  • Learn why Reason is exploding in popularity and why it s the future of React
  • Become familiar with Reason s syntax and semantics
  • Learn about Reason s ecosystem: BuckleScript and JavaScript interoperability
  • Learn how to build React applications with Reason
  • Learn how to use Reason s type system as a tool to provide amazing guarantees
  • Gain a solid foundation on which to continue your journey

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Feb 28, 2019
Length: 180 pages
Edition : 1st
Language : English
ISBN-13 : 9781789344233
Languages :

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
OR
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Product Details

Publication date : Feb 28, 2019
Length: 180 pages
Edition : 1st
Language : English
ISBN-13 : 9781789344233
Languages :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total $ 104.97
Learn Type-Driven Development
$38.99
ReasonML Quick Start Guide
$32.99
Getting Started with Qt 5
$32.99
Total $ 104.97 Stars icon
Banner background image

Table of Contents

9 Chapters
Introduction to ReasonML Chevron down icon Chevron up icon
Setting Up a Development Environment Chevron down icon Chevron up icon
Creating ReasonReact Components Chevron down icon Chevron up icon
BuckleScript, Belt, and Interoperability Chevron down icon Chevron up icon
Effective ML Chevron down icon Chevron up icon
CSS-in-JS (in Reason) Chevron down icon Chevron up icon
JSON in Reason Chevron down icon Chevron up icon
Unit Testing in Reason Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see www.packtpub.com/support and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to www.packtpub.com/account
  • To contact us directly if a problem is not resolved, use www.packtpub.com/contact-us
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.