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
$32.99
Paperback Feb 2019 180 pages 1st Edition
eBook
$9.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
$32.99
Paperback Feb 2019 180 pages 1st Edition
eBook
$9.99 $22.99
Paperback
$32.99
Subscription
Free Trial
Renews at $19.99p/m
eBook
$9.99 $22.99
Paperback
$32.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
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

Shipping Address

Billing Address

Shipping Methods
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
Estimated delivery fee Deliver to Thailand

Standard delivery 10 - 13 business days

$8.95

Premium delivery 5 - 8 business days

$45.95
(Includes tracking information)

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 : 9781789340785
Languages :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
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

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to Thailand

Standard delivery 10 - 13 business days

$8.95

Premium delivery 5 - 8 business days

$45.95
(Includes tracking information)

Product Details

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

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

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela