The document introduces ReasonML, a dialect of OCaml that compiles to JavaScript. It demonstrates various ReasonML features like static types, type inference, records, variants, pattern matching, and modules. It also shows how ReasonML helps make illegal states unrepresentable by enforcing boundaries on types from external data. The goal is to use ReasonML patterns and features to build robust, bug-free applications.
22. let car = "Blue Maruti 800";
'use strict';
var car = "Blue Maruti 800";
exports.car = car;
23. let car = "Blue Maruti 800";
/* This is fine. */
Js.log(car ++ " is sold out");
var car = "Blue Maruti 800";
console.log(
"Blue Maruti 800 is sold out"
);
24. let car = "Blue Maruti 800";
/* This is not OK. */
Js.log(car + 1);
We've found a bug for you!
This has type:
string
But somewhere wanted:
int
25. let myFirstCar = {
colour: "Blue",
make: "Maruti",
model: "800"
};
We've found a bug for you!
The record field colour can't
be found.
26. type car = {
colour: string,
make: string,
model: string
};
let myFirstCar = {
colour: "Blue",
make: "Maruti",
model: "800"
};
var myFirstCar = /* record */[
/* colour */"Blue",
/* make */"Maruti",
/* model */"800"
];
28. type colour = Red | Blue | White | Pink;
That’s a Variant.
29. type colour = Red | Blue | White | Pink;
These are the variant’s constructors.
30. type make = Maruti | HindustanMotors;
type model = EightHundred | Zen | Ambassador;
type colour = Red | Blue | White | Pink;
type car = {
make: make,
model: model,
colour: colour
};
let myFirstCar = {
var myFirstCar =
/* colour : Blu
/* make : Marut
/* model : Eigh
];
31. make: make,
model: model,
colour: colour
};
let myFirstCar = {
make: Maruti,
model: EightHundred,
colour: Blue
};
var myFirstCar =
/* colour : Blu
/* make : Marut
/* model : Eigh
];
32. ar = {
i,
tHundred,
e
var myFirstCar = /* record */[
/* colour : Blue */1,
/* make : Maruti */0,
/* model : EightHundred */0
];
33. model: EightHundred,
colour: Blue
};
let productionRun = car => {
switch (car.model) {
| EightHundred => "1983 to 2013"
}
};
var Caml_builtin_exception
require("./stdlib/caml_bui
function productionRun(car
var match = car[/* model
if (match !== 0) {
throw [
Caml_builtin_exc
/* tuple */[
".",
19,
2
]
];
} else {
return "1983 to 2013";
}
}
34. d
Run = car => {
odel) {
d => "1983 to 2013"
var Caml_builtin_exceptions =
require("./stdlib/caml_builtin_exceptions.js");
function productionRun(car) {
var match = car[/* model */2];
if (match !== 0) {
throw [
Caml_builtin_exceptions.match_failure,
/* tuple */[
".",
19,
2
]
];
} else {
return "1983 to 2013";
}
}
35. make: Maruti,
model: EightHundred,
colour: Blue
};
let productionRun = car => {
switch (car.model) {
| EightHundred => "1983 to 2013"
}
};
Warning number 8
You forgot to handle a possible
value here, for example:
(Zen|Ambassador)
36. model: EightHundred,
colour: Blue
};
let productionRun = car => {
switch (car.model) {
| EightHundred => "1983 to 2013"
| Ambassador => "1958 to 2014"
| Zen => "1993 to present"
}
};
function productionRun(car) {
var match = car[/* model */2];
switch (match) {
case 0 :
return "1983 to 2013";
case 1 :
return "1993 to present";
case 2 :
return "1958 to 2014";
}
}
37. Warning number 8
You forgot to handle a possible
value here, for example:
(Zen|Ambassador)
Use variants to
describe possibilities.
Got it.
38. type make = Maruti | HindustanMotors;
type model = EightHundred | Zen | Ambassador;
type colour = Red | Blue | White | Pink;
type car = {
make: make,
model: model,
colour: colour,
};
39. let abomination = {
make: HindustanMotors,
model: Ambassador,
colour: Pink
};
var abomination = /* record */[
/* colour : Pink */3,
/* make : HindustanMotors */1,
/* model : Ambassador */2
];
40. /* Nope, not available. */
let pink800 = {
make: Maruti,
model: EightHundred,
colour: Pink
};
/* You can buy one of these. */
let pinkZen = {
make: Maruti,
model: Zen,
colour: Pink
};
var pink800 = /* record */[
/* colour : Pink */3,
/* make : Maruti */0,
/* model : EightHundred */0
];
var pinkZen = /* record */[
/* colour : Pink */3,
/* make : Maruti */0,
/* model : Zen */1
];
41. /* Wut?! */
let marutiAmbassador = {
make: Maruti,
model: Ambassador,
colour: Pink
};
var marutiAmbassador = /* record
*/[
/* colour : Pink */3,
/* make : Maruti */0,
/* model : Ambassador */2
];
42. type car = {
make: make,
model: model,
colour: colour
};
/* Wut?! */
let marutiAmbassador = {
make: Maruti,
var marutiAmbassador = /* record
*/[
/* colour : Pink */3,
/* make : Maruti */0,
/* model : Ambassador */2
];
43. type ambiColour = JetBlack | OysterBlue | FireBrickRed | EcruBeige; /* and more */
type zenColour = BeamBlue | PearlSilver | BrightRed | FusionPink; /* and more */
type ehColour = BlueBlaze | SilkySilver | BrickRed | SuperiorWhite; /* and more */
type marutiModel = EightHundred(ehColour) | Zen(zenColour);
type hmModel = Ambassador(ambiColour);
type make = Maruti(marutiModel) | HindustanMotors(hmModel);
type car = { make: make };
44. type ambiColour = JetBlack | OysterBlue | FireBrickRed | EcruBeige; /* and more */
type zenColour = BeamBlue | PearlSilver | BrightRed | FusionPink; /* and more */
type ehColour = BlueBlaze | SilkySilver | BrickRed | SuperiorWhite; /* and more */
type marutiModel = EightHundred(ehColour) | Zen(zenColour);
type hmModel = Ambassador(ambiColour);
type car = Maruti(marutiModel) | HindustanMotors(hmModel);
51. let make = "Maruti";
let model = "Ambassador";
let colour = "FusionPink";
52. let productionRun = car => {
/* Production run as a string. */
};
let inStock = car => {
/**
* Boolean indicating whether
* car model is in stock.
*/
}
53. type ambiColour = JetBlack | OysterBlue | FireBrickRed | EcruBeige; /* and more */
type zenColour = BeamBlue | PearlSilver | BrightRed | FusionPink; /* and more */
type ehColour = BlueBlaze | SilkySilver | BrickRed | SuperiorWhite; /* and more */
type marutiModel = EightHundred(ehColour) | Zen(zenColour);
type hmModel = Ambassador(ambiColour);
type car = Maruti(marutiModel) | HindustanMotors(hmModel);
60. Make illegal states unrepresentable.
Parse all external data & enforce
boundaries.
Mint a module for every type.
Enforce invariants using the module
interface.
Perform compiler-assisted
refactoring.
Use equational reasoning.
Variants
Compiler
Pattern-matching
Functions
Modules
Abstract types
Referential transparency
62. let f = (~x, ~y=0) => Js.log2(x, y);
Warning number 16
This optional parameter in final
position will, in practice, not be
optional.
Reorder the parameters so that at least
one non-optional one is in final
position or, if all parameters are
optional, insert a final ().
Explanation: If the final parameter is
optional, it'd be unclear whether a
function application that omits it
should be considered fully applied, or
partially applied. Imagine writing `let
title = display("hello!")`, only to
realize `title` isn't your desired
result, but a curried call that takes a
final optional argument, e.g.
`~showDate`.
Formal rule: an optional argument is
considered intentionally omitted when
the 1st positional (i.e. neither
labeled nor optional) argument defined
after it is passed in.
let x = 1;
let y = 2.4;
Js.log(x + y);
We've found a bug for you!
This has type:
float
But somewhere wanted:
int
You can convert a float to a int
with int_of_float.If this is a
literal, you want a number
without a trailing dot (e.g.
20).
let make = _children => {
...component,
initialState: () => { x: "Hello" },
render: self => {
{ self.state.x |> ReasonReact.string; }
}
};
We've found a bug for you!
Is this a ReasonReact
reducerComponent or component
with retained props?
If so, is the type for state,
retained props or action
declared _after_
the component declaration?
Moving these types above the
component declaration should
resolve this!