Steps to learning Reason OCaml

Myer Nore
Mar 14, 2018 - 6 min read


What are Modules?

Modules group related methods, exceptions and types into a package. In addition, Reason provides module interfaces that make it easier to swap out one module for another module that fulfills the same interface.

Module Syntax - Basic Example

In contrast to types like variants and records, a module must begin with a capital letter. A variable that begins with a capital letter often indicates it is a module.

A module declaration looks generally like this: module <CapitalizedName> : <ModuleInterfaceType> = <implementation>;. The ModuleInterfaceType is optional as it is in Reason's type annotation in a let binding: let <variable name here> [: optionalTypeAnnotation] = "concreteValue".

Here is a basic example of a Person Module:

/* loading */

What problem do Modules solve?

In software, requirements evolve over time with feedback from a product's owner(s). It often happens that a system needs a new feature that the original engineers did not anticipate. This becomes especially complicated in large projects. For example, if you need to modify components A and B to provide a new feature, and components C-M depend on A while components G-Z depend on B, it can become difficult to figure out what will break if the engineers that built A and B are no longer around. This problem gets worse if clients rely on direct implementation details.

One strategy to is to ensure you can always swap out a component with another "of roughly the same size and shape," that is, with a component that fulfills the contract it currently guarantees its clients. As long as the interface that a component's clients use stays the same, the implementation is free to change.

Hypothetical example of why you should use interfaces

Let's say you are an engineer for a social networking site. Your product's component A used the Google Maps API to display a map of where users are logged in right now. It didn't use an interface and instead exposed the Google Maps data structures to its downstream components. Other coders ended up using Google Maps' data structures directly in the components they wrote, since that was the easiest thing to do. Then your product owner decided to extend your product's prescence in China, where Google Maps API doesn't work. Now you have to go into all of those downstream components and re-engineer how they are storing data ... ouch. Instead, you should have used an interface hiding how the information was stored, and if you need to switch out a different API provider, you won't have to change as many of your components.

Reason Type Checks and Modules

ReasonML's type checking ensures two things about the relationship between module and module type expressions:

  1. interface enforcement: if a module type declares a method, type or other entity, then the module that conforms to that interface must implement that entity.
  2. encapsulation: if it's not in the module type for a module, clients can't see that part of the implementation.

In the context of ReasonML, the terms interface, signature, and module type are all used interchangeably.

Example - module type enforcement

/* loading */

Everything in the module type must also be in the module. We left out y from the module M1, and it wouldn't compile.

Example - module type encapsulation

/* loading */

By declaring M2 to conform to interface S2, then everything not in S2 is "private" to the inside M2. Here, we tried to get the "private" property y outside of M2's closure, so Reason threw a compile time error.

Modules - Exercises

Fraction Module - Advanced

This exercise is Steffen Smolka's, taken from Cornell's CS 3110 Lecture 7 Lab.

Write a module implementing the following Fraction module type:

/* loading */

Your module should ensure that make, add, and mul return numbers in reduced form where the denominator is positive. See the Gradus Reason step Names and Functions for a sample implementation of Euclid's Algorithm.

Image Credit: Port Birch South - street 1 by cimddwc on Flickr

Edit this post here