Elm's Maybe.withDefault

· Allanderek's blog

#elm #compilation

In certain circles in the Elm community it is seen as more 'Elmish', that is more idiomatic, or more desirable to write code using functions to combine/inspect common datatypes. So this code:

1Maybe.withDefault 0 mInt

is more desirable than the following code which uses a case expression to achieve the same end:

1case mInt of
2    Nothing ->
3        0
4    Just x ->
5        x

One question that arises, is does one compile to more efficient code? Let's test this, we can easily write the following into an elm file and compile with optimisation turned on:

 1increment : Int -> Int
 2increment x = x + 1
 3
 4mIncrement : Maybe Int -> Int
 5mIncrement mInt =
 6    case mInt of
 7        Nothing ->
 8            1
 9        Just x ->
10            increment x
11
12decrement  : Int -> Int
13decrement x = x - 1
14
15mDecrement : Maybe Int -> Int
16mDecrement mInt =
17    mInt
18        |> Maybe.withDefault 0
19        |> decrement
20

I have deliberately written increment and decrement as separate functions so that this does not affect the compilation of either.

 1var $author$project$Main$decrement = function (x) {
 2	return x - 1;
 3};
 4var $elm$core$Maybe$withDefault = F2(
 5	function (_default, maybe) {
 6		if (!maybe.$) {
 7			var value = maybe.a;
 8			return value;
 9		} else {
10			return _default;
11		}
12	});
13var $author$project$Main$mDecrement = function (mInt) {
14	return $author$project$Main$decrement(
15		A2($elm$core$Maybe$withDefault, 0, mInt));
16};
17var $author$project$Main$increment = function (x) {
18	return x + 1;
19};
20var $author$project$Main$mIncrement = function (mInt) {
21	if (mInt.$ === 1) {
22		return 1;
23	} else {
24		var x = mInt.a;
25		return $author$project$Main$increment(x);
26	}
27};

So as perhaps expected the syntactical case expression compiles to more direct code. However it is possible that the Javascript engine can improve the performance of the more indirect code. Some benchmarking is required. However, there is a further problem, if the Nothing case is some expensive expression, then using Maybe.withDefault will evaluate that expression even when it is ultimately thrown away. This is one of the advantages of a lazy language.

There exists a special tool elm-optimize-level-2 which takes the Javascript code produced by the elm-compiler and improves it. I think there exists an opportunity for a tool that operates before the elm-compiler and translates idiomatic into more performant elm. Though of course the first step would be to do some benchmarking.