ReasonML Exception Handling

digitake
LambdaSide
Published in
3 min readDec 29, 2018

One thing I found it is kinda understandable and not understandable at the same time is the lack of articles, examples or anything that mentioned how to handle an exception in ReasonML. By nature, I don’t see much use of exception writing code in ReasonML. However, It can’t be avoided when we want to interop with JavaScript.

Since I can’t find the formal grammar on ReasonML exception, I will fall back to OCaml exception definition.

in Ocaml, Exception is merely an extensible variant of typeexn

To handle an exception in OCaml, we can use try/with construct which resemble a pattern matching:

try <expr> with
| <pat1> -> <expr1>
| <pat2> -> <expr2>
...

In ReasonML, we use the following clause:

try (<expr>) {
| <pat1> => <expr1>
| <pat2> => <expr2>
...
}

expr is evaluated and checked. If there is an exception thrown, then it tries to match the given pattern(Keep in mind that it is a normal pattern matching with the constraint of built-in type exn). Else, the result will be an evaluation of expr. The following code is an example of how to use exception in ReasonML syntax.

try (f) {
| SomeExn => doSomething()
| AnotherExn(value) => doSomethingWith(value)
...
}

The pattern in the clause must be a type of exn only. We will show later that this keyword can be replaced with switch of exception type.

Define exception type using exception keyword

To work with exceptions, we must know how to define it first. It is simple as defining a type. In fact,exception is syntactic sugar to add a new type to exn.Consider the following code:

type exn +=
| MyError;
exception MyAnotherError;

The first two lines are to add the new type called MyError using the extensible variant syntax. The line below does the same thing but using exception keyword. As we can see from the JavaScript’s counterpart:

var MyError = Caml_exceptions.create("MyError");var MyAnotherError = Caml_exceptions.create("MyAnotherError");

The exception definition is to define any exception we want to give a meaning in our program. However, in order to deal with exceptions from JavaScript, we must handle Js.Exn.Error(t)

Handling Exception from JavaScript side

Most of the exceptions raised from JavaScript side will become a value of type Js.Exn.Error(t). Let assume the scenario, we want to use a JavaScript function which can throw an exception.

exports.func = function(x) {
throw new Error("My Js Error");
return x;
}

We need to handle this exception properly.

[@bs.module "./test.js"] external func: (string) => string = "func";let result = try(func("test"){
|Js.Exn.Error(err) => Js.Exn.message(err)
|> Js.Option.getWithDefault("Some Js Error");""
|x => failwith(x);"Other Error"
}

The code above imports a functionfunc which is a JavaScript function and use the construct try to test if it throws an exception. If the exception throwing is of type Js.Exn.Error, we will use Js.Exn.message to extract the error message. Otherwise, it will failwith any other type of exceptions.

Note that the result of try must be of the same type of func result, in this case, a string.

To see why, let’s unfold try into normal pattern matching. We can achieve the same behavior using a pattern matching as follows:

[@bs.module "./test.js"] external func: (string) => string = "func";let result = switch(func("test")){
| exception(Js.Exn.Error(err)) => Js.Exn.message(err)
|> Js.Option.getWithDefault("Some Js Error");""
| exception(x) => failwith(x);"Other Error"
| value => value
}

Now things make more sense because value => value suggests that the type of this evaluation should return the value of the type of func result.

Hope this is useful when you are trying to google for ReasonML Exception Handling. That’s the whole reason while I wrote this. Feel free to leave me any comment or suggestion. Thanks!

--

--

digitake
LambdaSide

Lambda school of thought, minimalist, mathematical minded. Love AI, Functional, Logic.