alice
manual.


Alice Project

incompatibilities
with
SML


________ Overview ____________________________________________________

Most Alice extensions to SML'97 are conservative. There are some incompatibilies with SML'97 however. Most of them are quite pathological, caught at compile time, and can easily be fixed in an SML compatible way. This page describes known deviations and possible (backward-compatible) workarounds.

Also be aware of some limitations of the current version of Alice, which might produce additional incompatibilities.


________ Comments ____________________________________________________

Alice ML supports line comments, which start with the character sequence (*). Valid SML programs that contain a closing parenthesis as the first character of a regular comment (including nested ones) will hence be parsed incorrectly.

Workaround


________ Reserved words ______________________________________________

The following are reserved words in Alice and may not be used as identifiers:

	any       assert    assertd   constructor   exttype    fct
	finally   from      import    non           lazy       pack
	spawn     unpack    withfun   withval       _file_     _line_

The latter two are not valid SML identifiers, but would be parsed as a wildcard followed by an identifier in SML.

Workaround


________ Multiple open _______________________________________________

When open is used with multiple arguments this is taken as sugar for multiple open declarations. This results in slightly different scoping rules, when nested structures are present.

Example

structure A =
struct
    structure B = struct val x = 1 end
end
structure B = struct val x = "1" end

open A B

val y = x

According to Standard ML, y should have type string because x refers to B.x. In Alice ML however, x refers to A.B.x and hence y is assigned type int.

Workaround


________ Open and infix ______________________________________________

Open pulls in infix status. Opening a structure that

  1. contains infix declarations, and
  2. has not been constrained by a signature

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 *)

Workaround


________ Val rec _____________________________________________________

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 an artefact of the formal language specification and would introduce a function named NONE, hiding the constructor status of NONE. In Alice, they produces a type clash because they are interpreted as trying to match NONE with a lambda expression.

Note: This behaviour is consistent with SML'90 as well as several other SML implementations, and probably what the user would expect.

Workaround


________ Pattern matching ____________________________________________

Since Alice is a concurrent language, matches containing impure patterns - particularly ref patterns - may behave slightly odd. Patterns that are exhaustive in plain SML may not necessarily be so in Alice. Also, pattern matching may trigger side-effects, when a lazy future is requested by matching and the corresponding computation contains effects.

Example

fun f (ref false) = 1
  | f (ref true)  = 2

The match in this declaration will be flagged as unexhaustive by the Alice compiler. The reason is that pattern matching is not atomic, so a concurrent thread may have altered the reference between both tests - making them both fail! A particular example of a non-matching application is the following:

val rec r = ref (lazy (r := false; true))
f r

In this example, testing for the first clause will first dereference r and then request the lazy future, which determines to true, so that the clause does not match. In the meantime, the triggered computation has set r to false, hence the consecutive test, which dereferences r for a second time, will see false and fail likewise.

Workaround


________ Datatypes ___________________________________________________

Alice' structural datatypes come with some restrictions that are not present in SML. In particular, Alice demands that, whenever a datatype constructor is used in an expression, pattern, the corresponding type is visible. Dually, if a datatype is replicated, all its constructors must be visible.

Examples

The following program will not type-check:

datatype t = C
type t = int
val c = C

The datatype replication in the last line of the following snippet is invalid as well:

datatype t = C
datatype u = C | D
datatype v = datatype t

Though one does not usually write such code directly, these situations can appear implicitly through liberal use of open.

Workaround


________ Constructor arity ___________________________________________

For interoperability reasons, Alice 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.

Note:The same restriction is imposed by Moscow ML.

Note that 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

Examples

The following program will not elaborate in the current version of Alice:

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

Workaround


________ Namespaces __________________________________________________

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

functor Table() = struct (* ... *) end

structure Table  = Table()
structure Table' = Table()	(* error: Table is not a functor *)

Workaround


________ Sharing _____________________________________________________

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 (i.e. abstract) type constructors.

Alice relaxes the rules for sharing constraints and allows sharing of type constructors as long as one of the following conditions holds:

  1. both are identical type synonyms, or
  2. the type constructor introduced later (lexically) is abstract.

This makes sharing between datatypes possible in most cases. There are exceptions, however.

Example

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).

Workaround


________ Extended library ____________________________________________

Alice extends many of the structures and signatures defined by the Standard ML Basis Library. This may change the meaning of programs that open library structures, or use library signatures.

Examples

In the following snippet, the referenced function equal will be shadowed by the open declaration:

fun equal (a : 'a -> 'b, b : 'a -> 'b) = true
open Int
val b = equal (op+, op-)	(* error: type mismatch *)

Workaround



last modified 2007/03/14 17:49