The syntax and meaning of the various expression forms is described in this section.
Identifiers beginning with a lower case letter refer to pattern variables and named associations in let expressions.
Identifiers beginning with an upper case letter refer to data constructors.
A function application has the form:
<exprfun> <exprarg>
Association is to the left, so the parentheses may be omited in (f x) y.
If a function has n arguments, then it said to have arity n. For a function of arity n (where n > 1) function application denotes a new function with arity n - 1. This is also known as currying and it allows for partial function applications.
Partial data constructor application is permitted.
A lambda abstraction has the form:
\ <patt1> ... <pattn> -> <expr>
It denotes a unnamed function of arity n. Currently, the only kind of permitted pattern is an optionally signed variable.
The infix application of a binary operator <op> generally has the form:
<expression> <op> <expression>
There are two exceptions to this:
. has two special forms:The prefix notation is used for unary operators such as -, ¬:
<op> <expr>
There is an exception to this:
The select operator . has two special forms:
.<name>
or
.<data Constructor>
Semantically, operator applications are transformed to a standard function or type method application as specified in the following table:
| Symbol | Form | Associativity | Transformation | Notes |
|---|---|---|---|---|
. |
unary | right | (.) Root <name> or (.) dataCon <expr> Root |
Root select method or Root object construction |
¬ |
unary | right | (¬) <expr> | Boolean negation |
:: |
unary | right | (-) <type> | Type constant |
. |
binary | left | (.) <expr> <name> | Select by name |
- |
unary | right | (-) <expr> | Numeric negation |
^ |
binary | left | (^) <expr1> <expr2> | Numeric exponentiation |
* |
binary | left | (*) <expr1> <expr2> | Numeric multiplication |
/ |
binary | left | (/) <expr1> <expr2> | Numeric division |
mod |
binary | left | (modlt;expr1> <expr2> | Numeric modulus |
+ |
binary | left | (+) <expr1> <expr2> | Numeric addition |
- |
binary | left | (-) <expr1> <expr2> | Numeric subtraction |
< |
binary | left | (<) <expr1> <expr2> |
Less than |
<= |
binary | left | (<=) <expr1> <expr2> |
Less than or equal to |
= |
binary | left | (=) <expr1> <expr2> |
Equal to |
¬= |
binary | left | (¬=) <expr1> <expr2> |
Not equal to |
>= |
binary | left | (>=) <expr1> <expr2> |
Greater than or equal to |
> |
binary | left | (>) <expr1> <expr2> |
Greater than |
¬not |
binary | right | (¬) <expr> | Logical NOT |
&and |
binary | left | (&) <expr1> <expr2> | Logical AND |
|or |
binary | left | (|) <expr1> <expr2> | Logical OR |
#¬ |
unary | right | (#¬) <expr> | Bitwise one's complement |
<< |
binary | left | (<<) <expr1> <expr2> | Bitwise left shift |
>> |
binary | left | (>>) <expr1> <expr2> | Bitwise right shift |
#& |
binary | left | (#&) <expr1> <expr2> | Bitwise AND |
#^ |
binary | left | (#^) <expr1> <expr2> | Bitwise Exclusive OR |
#| |
binary | left | (#|) <expr1> <expr2> | Bitwise Inclusive OR |
: |
binary | right | Bind <name> <expr> | Construct (Name, Exp *) |
:= |
binary | right | See Assignment | Assignment operator |
-> |
binary | right | Function type operator | |
:: |
binary | left | See Type Constraint | Type constraint |
Property addition or destructive update is carried out by the assignment operator
Translation:
|
Type constraints may be used to restrict values to sub-types of their primary type.
Commonly used to constrain results of type * and object references (Ref),
they take the form:
Any expression may be constrained, but it must be consistent with the type of its context. The compiler will either statically check that the constraint is valid or insert a run-time type check, which may result in FAIL.
Translation:
|
There are two forms of conditional expression:
if expr1 then expr2 else expr3
if expr1 then expr2
For both, expr1 is evaluated. If the result is True, the value
of the conditional expression is expr2. Otherwise, the value is either
expr2 or Void for the second form.
The type of e1 must be Bool; See case for more explanation about the type of a conditional expression.
Translations:
|
|||||||||||||||||||||
A case expression has the following form:
case <expr>
{
<alt1>;
<alt2>;
...
<altn>;
<default>;
}
where
<alt1>
has the form:
<pati> -> <exprj> or <pati>, <pati + i> ... <pati + m> -> <exprj>
and <default>
otherwise -> <exprdef>
Semantically, <expr> is evaluated, then matched against the sequence of alternatives: <alt1> ... <altn> as described in patterns.
The matches are tried sequentially, from top to bottom. The first successful match causes evaluation of the corresponding alternative body, in the environment of the case expression extended by the bindings created during the matching of that alternative and by the declarations associated with that alternative. If no match succeeds, the result is unspecified. The last alternative can start with the keyword otherwise, which will always be successful.
A block expression has the following form:
{<sequence>}
where a sequence is
<expr1>
...
;<expr2>
...
;<exprn>
Translations:
|
seq x y is a standard function where the arguments are evaluated sequentially.
The type of x is required to be either statically or dynamically determined to be Void.
The evaluated type of seq x y is the evaluated type of y.
Let expressions have the form:
let {<decl1>; <decl2>; ... ;<decln>} in <expr>
The value is <expr> where the set of mutually recursive declarations has scope both in it and the right-hand side of the declarations.
Last update: 11 October, 2005