5 This page contains brief explanations of some recurring sources of
6 confusion and problems that SML newbies encounter.
8 Many confusions about the syntax of SML seem to arise from the use of
9 an interactive REPL (Read-Eval Print Loop) while trying to learn the
10 basics of the language. While writing your first SML programs, you
11 should keep the source code of your programs in a form that is
12 accepted by an SML compiler as a whole.
14 == The `and` keyword ==
16 It is a common mistake to misuse the `and` keyword or to not know how
17 to introduce mutually recursive definitions. The purpose of the `and`
18 keyword is to introduce mutually recursive definitions of functions
19 and datatypes. For example,
25 | isEven n = isOdd (n-0w1)
28 | isOdd n = isEven (n-0w1)
35 datatype decl = VAL of id * pat * expr
37 and expr = LET of decl * expr
41 You can also use `and` as a shorthand in a couple of other places, but
44 == Constructed patterns ==
46 It is a common mistake to forget to parenthesize constructed patterns
47 in `fun` bindings. Consider the following invalid definition:
52 | length h :: t = 1 + length t
55 The pattern `h :: t` needs to be parenthesized:
60 | length (h :: t) = 1 + length t
63 The parentheses are needed, because a `fun` definition may have
64 multiple consecutive constructed patterns through currying.
66 The same applies to nonfix constructors. For example, the parentheses
71 fun valOf NONE = raise Option
75 are required. However, the outermost constructed pattern in a `fn` or
76 `case` expression need not be parenthesized, because in those cases
77 there is always just one constructed pattern. So, both
81 val valOf = fn NONE => raise Option
89 fun valOf x = case x of
96 == Declarations and expressions ==
98 It is a common mistake to confuse expressions and declarations.
99 Normally an SML source file should only contain declarations. The
100 following are declarations:
106 functor Fn (...) = ...
113 structure Struct = ...
127 To specify a side-effecting computation in a source file, you can write:
137 SML has a fairly intricate built-in notion of equality. See
138 <:EqualityType:> and <:EqualityTypeVariable:> for a thorough
144 It is a common mistake to write nested case expressions without the
145 necessary parentheses. See <:UnresolvedBugs:> for a discussion.
150 It used to be a common mistake to parenthesize `op *` as `(op *)`.
151 Before SML'97, `*)` was considered a comment terminator in SML and
152 caused a syntax error. At the time of writing, <:SMLNJ:SML/NJ> still
153 rejects the code. An extra space may be used for portability:
154 `(op * )`. However, parenthesizing `op` is redundant, even though it
155 is a widely used convention.
160 A number of standard operators (`+`, `-`, `~`, `*`, `<`, `>`, ...) and
161 numeric constants are overloaded for some of the numeric types (`int`,
162 `real`, `word`). It is a common surprise that definitions using
163 overloaded operators such as
167 fun min (x, y) = if y < x then y else x
170 are not overloaded themselves. SML doesn't really support
171 (user-defined) overloading or other forms of ad hoc polymorphism. In
172 cases such as the above where the context doesn't resolve the
173 overloading, expressions using overloaded operators or constants get
174 assigned a default type. The above definition gets the type
178 val min : int * int -> int
181 See <:Overloading:> and <:TypeIndexedValues:> for further discussion.
186 It is a common mistake to use redundant semicolons in SML code. This
187 is probably caused by the fact that in an SML REPL, a semicolon (and
188 enter) is used to signal the REPL that it should evaluate the
189 preceding chunk of code as a unit. In SML source files, semicolons
190 are really needed in only two places. Namely, in expressions of the
202 let ... in exp ; ... ; exp end
205 Note that semicolons act as expression (or declaration) separators
206 rather than as terminators.
214 == Unresolved records ==
219 == Value restriction ==
221 See <:ValueRestriction:>.
224 == Type Variable Scope ==
226 See <:TypeVariableScope:>.