ReasonML
First impressions about ReasonML, a functional programming language that combines the power of OCaml with JavaScript interoperability
Published
- 4 min read
ReasonML Programming Language
What is ReasonML? Where does it come from? What can I do with it?
ReasonML is a functional programming language offering a modern syntax for OCaml, designed to work seamlessly with JavaScript via BuckleScript. If you’re curious about how ReasonML compares to OCaml, check out the official documentation.
Originally created at Facebook, ReasonML caught my attention through Nick Graf’s Egghead course, Get Started with Reason. This post evolved from my notes while following the course, so big thanks to him for the insightful code examples.
For a deeper dive into ReasonML, Dr. Axel Rauschmayer’s excellent book, Exploring ReasonML and Functional Programming, is available to read online for free.
What I Like and Dislike So Far
What I Like
- Inferred types simplify the coding process.
- Custom types and variants enhance expressiveness.
- Exhaustive compiler checks ensure you handle all switch cases.
- Command-line code suggestions are incredibly helpful.
- Strong JavaScript and OCaml interoperability.
- Lexical scoping keeps things predictable.
- The
if
statement is an expression that returns a value. - The syntax for switch expressions is clean and intuitive.
- Objects (or records) are defined similarly to TypeScript.
- JavaScript-inspired destructuring and spread operators.
- Combination of variants and switch expressions is powerful.
- Null safety: Variants
None
andSome
replace null. - Partial function application and automatic currying.
- Labeled parameters allow arguments in any order.
- Support for optional parameters.
- Pipe operator for clean function composition.
- Direct equality comparison for nested structures.
- Both structural (
==
) and referential equality (===
). - Robust pattern matching for expressive logic.
What I Dislike
- Shadowing allows variables to be redefined.
- The
++
operator for string concatenation feels counterintuitive. - Built-in functions have underscores in their names.
- Syntax can feel cluttered with excessive semicolons.
Code Examples
Here are some illustrative 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
Back to the top ↑