I'm a big fan of creating data structures that make representing invalid states impossible, so I wanted to ask how I could represent a non empty list in reasonml?
Since it's possible to pattern match on lists like [] and [head, ...rest] I thought it would be easy to represent a non empty list, but I haven't found a way yet.
Update: Thanks to the enlightening answers below I was able to come up with something that really strikes my tune:
module List = {
include List;
type nonEmpty('a) = ::('a, list('a));
let foldNonEmpty = (type a, fn, l: nonEmpty(a)) => switch(l) {
| [head, ...tail] => fold_left(fn, head, tail)
};
}
module Number = {
let min = List.foldNonEmpty(Pervasives.min);
let max = List.foldNonEmpty(Pervasives.max);
}
Number.min([]); // illegal :D
Number.min([1]); // legal
Don't know how you guys feel about it, but I think it's awesome. Thanks!
You can also define a new list type without GADT as:
Compared to the GADT solution, you lose some syntactic sugar, because the syntax
implicitly adds a terminal
[]but the[x, ...y]syntax still worksOtherwise, the encoding
is even simpler and does not rely on potentially surprising syntactic constructions.
EDIT:
::, the infix variant constructorIf the part of the definition with
::seems strange, it is because it is a left-over of corner case of the OCaml syntax. In Ocaml,is written
which is itself the infix form of
(This the same prefix form of standard operator :
1 + 2can also be written as(+)(1,2)(in Reason) ) And the last form is also the prefix form of[x,...l]in reason. In brief, in Reason we havewith the OCaml syntax as the missing link between the two notations.
In other words
::is an infix constructor (and the only one). With recent enough version of OCaml, it is possible to define your own version of this infix constructor withThe same construction carries over in Reason as
Then if you write
[a, ...b]it is translated to(::)(a,b)with::as your newly defined operator. Similarly,is in fact a shortcut for
So if you define both
[]and::, for instance in this silly exampleyou end up with a syntax for exotic lists, that works exactly the same as standard lists.