23.1 val declarations : valDecl
Syntax of val declarations is given below.
valDecl | ::= | val tyvarSeq valBind |
valBind | ::= | valBind1 |
valBind1 and valBind | ||
valBind1 | ::= | pat = exp |
In this declaration, the variables appearing in patterns valBind must be distinct. These variables are simultaneously defined, whose scope is the entire valDecl declaration and the declarations that follows.
The type variable declaration tyvarSeq in valDecl delimit their scope. These type variables must be generalized at the top-level of each valBind1 declaration.
23.1.1 val declaration interface : valSpec
For each variable defined in a val declaration, the following form of interface specification must be declared.
valBindInterface | ::= | val id : ty |
For example,for val declaration
val (x,y) = (1,2)
the following two interface specification must be given.
val x : int
val y : int
23.1.2 val declaration evaluation
Val declaration of the form
val pat = exp and pat = exp
is evaluated in the following two steps.
Structured pattern evaluating
A val declaration with a structured pattern pat is first transformed to sequence of val declarations for the set of variables in the pattern pat.
If the pattern pat does not contain constructor or constant, then the transformation is done by recursively decompose pat and exp pair to a sequence of pairs of a sub-pattern and a sub-expression. This is done in the following steps.
-
1.
Each pattern pat is decomposed into sub-patterns according to the structure of pat. When pat has a type constraint, then the corresponding type constraint is attached to each of the decomposed sub-patterns.
-
2.
For each decomposed sub-pattern of pat, the corresponding sub-expression is generated from the expression exp by applying the code to extract the corresponding value to exp.
-
3.
If a sub-pattern is a layered pattern of the form as , the additional code to bind to the entire value is generated.
-
4.
Finally, the following from of val declarations is generated from the sequence of pairs of a variable and an expression obtained from the above transformation steps.
val =
and =
This decomposition process enables the variables in structured patterns to have rank-1 polymorphic types as far as possible. However, the above transformation cannot be applied to val declarations with constructors and constants, since these val declarations may raise exception at runtime. A val declaration containing constructors and constants is transformed to the following val declaration with a variable.
val = case (exp, , exp) of
(pat, , pat) => (,,)
| _ => raise Bind
val = #1
and = #
23.1.3 Example of val declarations and interface
The following are simple examples in the interactive mode.
# val (x,y) = (print "SML#
\
n", fn x => fn y => (x,y));
SML#
val x = () : unit
val y = fn : [’a. ’a -> [’b. ’b -> ’a * ’b]]
# val (z, w, 1) = (print "SML#\
n", fn x => fn y => (x,y), 1);
(interactive):2.8-2.8 Warning:
(type inference 065) dummy type variable(s) are introduced due to value
restriction in: y
(interactive):2.4-2.57 Warning: binding not exhaustive
(x, y, 1) => ...
SML#
val z = () : unit
val w = fn : fn : ?X7 -> ?X6 -> ?X7 * ?X6
The following is a simple example of a source file and an interface file in separate compilation.
Version.sml file:
val (version, releaseDate) = ("4.0.0", "2021-04-06")
Version.smi file: val version : string val releaseDate : string |