The prototype consists of an online text editor (based on Monaco Editor).
Computed types are printed as lenses (above each definition). In case of error, the error message is printed instead.
A program is a sequence of toplevel statements:
prog ::= stmt*
stmt ::= type id [(tvar, ..., tvar)] = t [and ...]
| abstract type id [([+|-]tvar, ..., [+|-]tvar)]
| let gid param* = e [and ...]
| val gid [: t]
param ::= pat
| ( pat : t )
A statement can be either
Identifiers come in several flavours :
gid ::= id | ( op )
id ::= [a-z_][a-zA-Z0-9_']*
cid ::= [A-Z][a-zA-Z0-9_']*
tvar ::= '[a-zA-Z][a-zA-Z0-9_]*
t ::= simple_type
| t -> t
| t ,..., t
| t :: t
| [ tregex ]
| { id :[?] t;...; id :[?] t [..]}
| t | t
| t & t
| t \ t
| ~ t
| t where id tvar* = t [and ...]
simple_type ::= b
| id [(t, ..., t)]
| cid [(t)]
| tvar
| (t)
b ::= ()
| lit
| (int..int) | (..int) | (int..) | (..)
| any | empty | tuple | tuplen | true | false | bool
| int | char | unit | string | list | nil
Types are the usual set-theoretic types with tuple (product), arrow and record constructors and union, intersection, difference and negation operators. A sequence type constructor is provided as well. The content of a sequence type can be a regular expression over types, using the usual operators (*, + and ?). For instance, the type [ 'a* (bool|int)? ] is equivalent to the type definition
t where t = 'a::t | s and s = [] | (bool | int)::[]
Record types are given by the list of their fields, that is labels associated with a type. A label may be absent (denoted by :?). Open record types end their field list with ... Polymorphic types can be instantiated by giving a list of type parameters. Basic types consists of literals (which denote their own singleton type), augmented with integer interval types, and set of builtin type identifiers.
e ::= lit
| gid
| cid [(e)]
| (e : t)
| (e :> t)
| (e :>> t)
| (e :>>> t)
| { [e with] id=e;...;id=e }
| [ e; ... ;e ]
| e ,..., e
| fun param ... param -> e
| let gid = e in e
| let (pat) = e in e
| if e [is t] then e else e
| fst e | snd e | hd e | tl e
| match e with [|] pat -> e | ... | pat -> e end
| e ; e
| if e [is t] do e [else e] end
| while e [is t] do e end
lit ::= [0-9]+
| 'char'
| "char*"
| float
| () | false | true | []
Expressions can be
pat ::= :simple_type
| id
| lit
| cid [(pat)]
| pat,...,pat | pat|pat | pat&pat
| (pat)
| [ pat; ... ;pat ]
| { id [= pat];...; id [= pat] [..]}
| id = lit
Patterns are essentially types with capture variables. For instance, the following expression
match y with
| :[ int* ] -> false
| ( x & :bool, :int ) | x = false -> x
end
First checks whether y is a list of integers, in which case it returns false. Or, it tests whether either y is a pair of a Boolean and an integer, and captures the Boolean in x, or defines x to the constant false, and then returns x.