Reason
  • Docs
  • Try
  • API
  • Community
  • Blog
  • Languages iconEnglish
    • 日本語
    • Deutsch
    • Español
    • Français
    • 한국어
    • Português (Brasil)
    • Русский
    • Українська
    • 中文
    • 繁體中文
    • Help Translate
  • GitHub

›Language Basics

Intro

  • What & Why
  • Getting started

Setup

  • Installation
  • Editor Plugins
  • Format (refmt)

Language Basics

  • Overview
  • Let Bindings
  • Primitives
  • Basic Structures
  • Types
  • Records
  • Variants
  • Options and nullability
  • Functions
  • Recursion
  • Destructuring
  • Pattern Matching
  • Mutable Bindings
  • Loops
  • Modules

Advanced Features

  • JSX
  • External
  • Exception
  • Object

JavaScript

  • Melange
  • Interop
  • Syntax Cheatsheet
  • Pipe First
  • Promise
  • Libraries
  • Converting from JS

Extra

  • Frequently Asked Questions
  • Extra Goodies
  • REPL (rtop)
Edit

Modules

Quick overview: Modules

Modules are a way to group type definitions, let bindings, and other nested modules. They are a helpful tool to keep your code neat and organized.

The Basics

Create a module with the module keyword:

module Duration = {
  type t = int;
  let fromSeconds = value => value;
  let add = (x, y) => x + y;
};

The Duration module can now be used from other places:

let fiveSeconds = Duration.fromSeconds(5);
let tenSeconds = Duration.add(fiveSeconds, fiveSeconds);

Note: Module names must start with a capital letter.

Files are Modules

Every Reason (.re) file creates a module for the contents of that file. This is commonly how modules are created and code splitting occurs.

A file named Duration.re (or duration.re) will result in a module named Duration.

Opening Modules

The contents of a module can be made available in the current scope with the open keyword:

open Duration;

let fiveSeconds = fromSeconds(5);
let tenSeconds = add(fiveSeconds, fiveSeconds);

Warning: open should be used sparingly. Opening many modules will pollute the global namespace and can unexpectedly overwrite functions with common names. If open still seems necessary, consider using a local open instead:

Local Opens

The scope in which a module is open can be restricted in several ways. It can be limited to a block scope by using open within that block:

let getDuration = () => {
  open Duration;
  let five = fromSeconds(5);
  let ten = add(five, five);
  ten;
};

/* Error: Unbound value */
fromSeconds(5);

Or special syntax can be used Module.(), Module.{}, or Module.[]. In each of these cases the module is only open between the left and right symbols.

let ten = Duration.(add(fromSeconds(3), fromSeconds(7)));

let timer = Duration.{contents: fromSeconds(10)};

/* A list of durations */
let durations = Duration.[fromSeconds(1), fromSeconds(2), fromSeconds(3)];

/* Error: Unbound value */
fromSeconds(5);

Opens Do Not Copy

Opening a module only affects the visibility of that module's contents. It will not copy the contents of the module to the location of the open. This does not work for example:

module DurationCopy = {
  open Duration;
  let ten = fromSeconds(10);
};

/* Error: Unbound Value */
let twenty = DurationCopy.fromSeconds(20);

A different keyword, include, does provide this copy behavior. It is covered later.

Including Modules

The include keyword copies the contents of a module into another module. This can provide a sense of inheritance by always including a default set of functions.

module BaseItem = {  
  let isEnabled = (user) => user.isLoggedIn;
  let run = () => "Do Nothing.";
};

module Hello = {
  include BaseItem;  
  let run = () => "Hello World!";
};

/* Can safely use the interface of BaseItem even if isEnabled does not change */
if (Hello.isEnabled(currentUser)) {
  print_endline(Hello.run());
};

Module Types

Explicit types can be written for modules:

module type Duration = {
  type t;
  let fromSeconds: int => t;
  let add: (t, t) => t;
};

This type can be applied with : when a module is created. The module type specifies exactly what is exposed from a module, anything extra will be hidden.

module Duration: Duration = {
  type t = int;
  let fromSeconds = value => value;
  let add = (x, y) => x + y;

  /* The module type hides this */
  let extraStuff = () => ();
};

/* Error: Unbound value */
Duration.extraStuff();

Including Module Types

Module types can also be extended using the include keyword:

module type Printable = {
  type printable;
  let print: printable => string;
};

module type PrintableDuration = {
  include Duration;
  include Printable;
};

Accessing Implicit Module Type

Sometimes you may need access to the type of a module, but that module will not have an explicit type defined. Use (module type of ModuleName) to access the type.

module type PrintableDuration = {
  include (module type of Duration);
  include Printable;
};

Interface Files

Interface files (.rei files) are module types. The file creates a module type and automatically applies it to the .re file with the same name.

In the above examples we instead may have written two files:

/* Duration.rei */
type t;
let fromSeconds: int => t;
let add: (t, t) => t;
/* Duration.re */
type t = int;
let fromSeconds = value => value;
let add = (x, y) => x + y;

This would give the same behavior as using explicit modules and module types.

Functors

Functors are like functions that create modules. This is an advanced topic that can be very powerful. Here is a basic example:

module type Stringable = {
  type t;
  let toString: (t) => string;
};

module Printer = (Item: Stringable) => {
  let print = (t: Item.t) => {
    print_endline(Item.toString(t));
  };

  let printList = (list: list(Item.t)) => {
    list
    |> List.map(Item.toString)
    |> String.concat(", ")
    |> print_endline;
  };
};

module IntPrinter = Printer({
  type t = int;
  let toString = string_of_int;
});

IntPrinter.print(10); // 10
IntPrinter.printList([1, 2, 3]); // 1, 2, 3
← LoopsJSX →
  • The Basics
  • Files are Modules
  • Opening Modules
    • Local Opens
    • Opens Do Not Copy
  • Including Modules
  • Module Types
    • Including Module Types
    • Accessing Implicit Module Type
  • Interface Files
  • Functors