bilities
with SML") ?>
Most Alice extensions to SML'97 are conservative. There are some incompatibilies to SML'97 however. Most of them are quite pathological, caught on compile time, and can easily be fixed in an SML compatible way.
Another limitation of Stockhausen Operette 1 is the lack of support for overloading: the toplevel arithmetic operators are only defined for type int. Moreover, Stockhausen currently does not distinguish equality types: equality is permitted on any type. Both features will probably be subsumed when we add something similar to type classes to the language in a later step.
The following are reserved words in Alice and may not be used as identifiers:
any constructor fct from import non pack unpack when withfun withval
Open pulls in infix status. Opening a structure that
will change the infix environment, while in SML it would not.
Example:
structure S = struct infix ++ fun l1++l2 = l1 @ l2 end open S val l = ++([1],[2]) (* error: misplaced infix *)
Fixes:
signature SIG =
sig
val ++ : 'a list * 'a list -> 'a list
end
structure S: SIG =
struct
infix ++
fun l1++l2 = l1 @ l2
end
open S
val l = ++([1],[2])
val l = op++([1],[2])
Recursive value bindings do not remove constructor status on the identifiers bound. You cannot bind functions to an identifier that was a constructor previously.
Example:
val rec NONE = fn x => x fun NONE x = x
Both these declarations are legal in SML'97 due to some artefact of the formal language specification and would introduce a function named NONE, hiding the constructor status of NONE. In Alice it produces a type clash because it is interpreted as trying to match NONE with a lambda expression. This is consistent with SML'90 and other SML implementations like SML/NJ, however, and probably what the user would expect.
Fix:
For interoperability reasons, Stockhausen currently has the concept of syntactic arity for constructors. For example, in
type t = int * real
datatype t = A of int * real | B of {a:bool, b:string} | C of t
constructor A and B both have arity 2, while C has arity 1. Usually, syntactic arity can be ignored. However, signature matching is restricted to disallow changing the syntactic arity of constructors.
Example:
The following program will not elaborate in the current version of Stockhausen:
signature S1 =
sig
datatype t = C of int * real
end
structure M1 :> S1 = (* error: mismatch *)
sig
type u = int * real
datatype t = C of u
end
Neither will:
type u = int * real
signature S2 =
sig
datatype t = C of u
end
structure M2 :> S2 = (* error: mismatch *)
sig
datatype t = C of int * real
end
Fix:
In most cases, modules can be rewritten by either expanding type synonyms or by introducing auxiliary type synonyms:
structure M1 :> S1 =
sig
type u = int * real
datatype t = C of int * real
end
structure M2 :> S2 =
sig
type u = int * real
datatype t = C of u
end
Transformations can get tedious in the case of higher-order functors, however.
Note that the syntactic arity is calculated after elimination of derived forms. Therefore C has arity 3 in the following example:
datatype t = C of u withtype u = int * int * string
Alice provides higher-order functors. To integrate them smoothly into the language it was necessary to give up the separation between namespaces for structures and those for functors - both are modules.
This may break programs that declare structures and functors with identical names.
Example:
The following program will not compile:
functor Table() = struct (* ... *) end
structure Table = Table()
structure Table' = Table() (* error: Table is not a functor *)
Fix:
Rename your functors or structures appropriately. It is a good idea to stick to naming conventions that denote functors with names like MakeTable.
Because of syntactic ambiguity with uses of parameterized signatures, Alice does not support the multiple include derived form.
Example:
signature S = sig include A B (* error: A is not parameterized *) end
Fix:
Split it into several include specifications:
signature S =
sig
include A
include B
end
In Alice, datatypes are not generative, but are just structural types similar to records. This has an impact on the use of sharing constraints, which require flexible (ie. generative) type constructors.
Alice relaxes the rules for sharing constraints and allows sharing of type constructors as long as one of the following conditions holds:
This makes sharing between datatypes possible in most cases. There are exceptions, however.
Example:
Exceptions are signatures like:
signature A =
sig
type t
end
signature B =
sig
datatype t = C
end
signature S =
sig
structure A : A
structure B : B
sharing type A.t = B.t (* error: types incompatible *)
end
Signature S will not elaborate because type B.t is specified after A.t and is neither abstract nor identical to A.t (which is abstract).
Fixes:
Signature S can be made valid by reordering structure specifications:
signature S =
sig
structure B : B
structure A : A
sharing type A.t = B.t
end
Suitable reordering is not always possible, however.
In general, we consider sharing constraints an obsolete feature of SML. Use where constraints instead (Alice as well as SML/NJ support where constraints for whole structures).