ReasonML Programming Language

What is ReasonML? Where does it come from? What can I do with it?

ReasonML is an object-functional programming language that provides a different syntax for writing OCaml code and can be transpiled into JavaScript code using BuckleScript. A comparison between OCaml and ReasonML can be found on ReasonML’s official documentation.

The ReasonML programming language was created at Facebook and I found out about it thanks to Nick Graf’s Egghead course Get Started with Reason. I started taking notes while watching the course and I ended up with this post (so thank him for the code examples).

If you want to know more about the language, Dr. Axel Rauschmayer has written a wonderful book about it that you can read online for free: Exploring ReasonML and functional programming.

What I Like and Dislike so Far

I like…

  • Inferred types
  • The possibility of creating custom types and variants
  • The compiler warns you if your switches are not exhaustive (if you’re forgetting cases)
  • Code suggestions underneath the command line are cool
  • Compatibility with JS and OCaml
  • Lexical scoping
  • If is an expression that can be evaluated into a value (in other languages it is only an statement)
  • Syntax of switch expressions
  • Objects (or records) defined in a similar way as in TypeScript
  • Destructuring objects (records) in a similar way as in JavaScript
  • Spread operator as in JavaScript
  • Combinations of variants with switch expressions are great
  • You can match specific cases in a switch
  • There’s no null: variants None and Some can be used instead
  • You can partially apply arguments in functions (automatic currying)
  • Labeled parameters (you can apply then in any order you want)
  • Optional parameters
  • Pipe operator for function composition
  • Nested structures can directly be compared for equality
  • Structural == and referential equality === operators
  • Powerful pattern matching

I dislike…

  • Shadowing is allowed (let variables can be redefined)
  • Operator ++ for concatenating strings
  • Underscores in the built-in functions’ names
  • Too many semicolons

Code Examples

let foo = {
  let a = 40;
  let b = 1;
  a + b + 1;
}; // this will bind 42 to the name `foo`

let isMorning = true;
// This binds "Good Morning" to the name `greeting`
let greeting = if (isMorning) {"Good Morning"} else {"Hello"};

// A switch expression
let greeting = stranger =>
  switch (stranger) {
    | Teacher => "Hey professor"
    | Director => "Hello director"
    | Student("Richard") => "Still here Ricky?"
    | Student(anyOtherName) => "Hey, " ++ anyOtherName ++ "."
    | _ => "unknown"
  };

// A person type definition
type person = {
  name: string,
  age: int,
  mutable mood: string, // mood is the only mutable field in this type
};

// A record of type person
let tim = {
  name: "Tim",
  age: 52,
  mood: "happy"
};

// Destructuring a person type into variables timsAge and timsName
let {age: timsAge, name: timsName} = tim;

// Custom type answer (tagged union or variant)
type answer =
  | Yes
  | No
  | Maybe;

// Further assignments automatically infer the type
let isItRaining = Maybe; // It infers type `answer`

// You can define functions like this (in this case, types are optional, since they
// can be inferred
let add: (x: int, y: int) : int => x + y;

// A function with labelled and optional parameters
let name = (~firstName="Defaultname", ~middleName=?, ~lastName, ()) => {
  switch (middleName) {
  | Some(value) => firstName ++ " " ++ value ++ " " ++ lastName
  | None => firstName ++ " " ++ lastName
  };
};

// Pipe operators example: find the largest element smaller than 4
[8, 3, 6, 1]
  |> List.sort(compare)
  |> List.rev
  |> List.find(x => x < 4);

// Recursive functions (without rec, the function cannot call itself)
let rec countBack = x => {
  if (x > 1) {
    print_int(x);
    countBack(x - 1);
  };
};

// There are tuples too (unlike lists, they can contain elements of different types)
("this is", 1, "tuple", "of four elements")

// And there are arrays. Unlike lists, they're mutable
[|3, 4|]

// A pattern matching example
switch ([|"a", "b", "c"|]) {
| [|"a", "b", _|] => print_endline("a, b and something")
| [|_, x, y|] => print_endline("something and " ++ x ++ " " ++ y)
| _ => print_endline("An Array")
};

// Example Math module
module Math = {
  let pi = 3.1415;
  let add = (x, y) => x + y;
};

// Then access everything using dot notation
Math.pi; // Returns 3.1415