Overview
The language has no type declarations or type annotations; all types are inferred by a Hindley-Milner-style type inference engine that is part of the type checker. Unlike Standard ML, the language incorporates Ohori-style record polymorphism. This means that, for example, the following function addab can subsequently be applied to any record argument as long as it has immutable integer fields a and b:
fun addab r = r.a + r.b
in
addab { a = 5, b = 7, c = "hello" } -
addab { b = 23, a = 0 } *
addab { z = 1, a = 22, y = 15, b = -1, x = 4 }
Syntax
Notice that this grammar, as written, is highly ambiguous.
WARNING This syntax is out-of-date.
program -> functions * mainfun
functions -> fun fundecl (and fundecl)*
fundecl -> name formals = exp
formals -> varpat | ( [varpat (, varpat)*] )
varpat -> _ | name
exp -> let varpat = exp in exp
| functions in exp
| if exp then exp else exp
| case exp of match
| exp with recordexp
| exp where recordexp
| exp binconn exp
| exp exp
| unaryop exp
| exp . label
| exp ! label
| exp ! label := exp
| name
| true
| false
| integer
| string
| ( )
| ( exp )
| ( exp , exp (, exp)* )
| ( exp ; exp (; exp)* )
| [ (exp [, exp]*) ]
| recordexp
match -> nilcase | conscase
| conscase | nilcase
nilcase -> [ ] => exp
conscase -> varpat :: varpat => exp
binconn -> boolconn | cmpop | arithop | ::
boolconn -> andalso | orelse
cmpop -> == | > | >= | <> | < | <=
arithop -> + | - | * | / | %
unaryop -> - | isnull | hd | tl | not
label -> name | integer
recordexp -> { [fieldexp (, fieldexp)*] }
fieldexp -> name = exp | name := exp
mainfun -> fun main ( varpat , varpat ) = exp
name -> . . .
integer -> . . .
string -> ". . . ”
Expressions
literal data
MLPolyR programs can use the following constants:
- boolean - true, false
- numerical - integer
- string
- unit ( )— the record/tuple with no fields
- lists [ . . . ]
- records { . . . }
- tuples ( . . . )
identifiers
Identifiers (name) in MLPolyR name values, not locations. They are not mutable. The only form of assignment is update of mutable record fields.
binary operations
In general, binary operations have the form e1 op e2 where op is one of:
- short-circuiting logical or: orelse — boolean arguments and results
- short-circuiting logical and: andalso — boolean arguments and results
- comparisons: == <> < > <= >= — integer operands, boolean result
- list cons: ::— element and list operands, list result
- addition and subtraction: + - — integer operands and result
- multiplication and division: * / % — integer operands and result
These operators are listed in order of increasing precedence.
unary operations
There are five unary operations:
- boolean negation: not e— boolean argument, boolean result
- arithmetic negation: - e— integer argument, integer result
- empty list test: isnull e— list argument, boolean result
- list head: hd e— list argument, element result
- list tail: tl e— list argument, list result
conditional expression
An if expression evaluates its boolean condition and depending on the outcome proceeds to evaluate either the then branch or the else branch. The expression that is not needed does not get evaluated. Notice that e1 andalso e2 and e1 orelse e2 are equivalent to if e1 then e2 else false and if e1 then true else e2, respectively.
Built-in functions
MLPolyR programs are compiled in a global environment containing a binding for the following record value:
val String : { toInt : string -> int,
fromInt : int -> string,
inputLine : () -> string,
size : string -> int,
output : string -> (),
sub : string * int -> int,
concat : string list -> string,
substring : string * int * int -> string,
compare : string * string -> int }
The elements of this record can be used to perform simple I/O tasks and string manipulation.