SML/NJ has a newer version of the Compilation Manager (CM) than when the book was written, so you'll have to make a few small changes. First, to load your code in SML/NJ, you need to provide sources.cm as an argument to the sml command:
% sml -m sources.cm
The -m flag causes SML/NJ to compile and load your files eagerly, which will catch errors sooner. You can try omitting the -m flag and see what happens.
If you are running SML/NJ from Emacs's SML mode,
set the compilation command to
CM.make("sources.cm")
.
You also need to make three changes to your sources.cm:
sml-nj.cm
need to be
prefixed by $/
.$/basis.cm
and $/ml-yacc-lib.cm
.tiger.lex
line to read tiger.lex: mllex
, which tells CM
to start the lexer generator in ML-LEX compatibility
mode.Here is my sources.cm from Homework 1:
Group is driver.sml errormsg.sml tokens.sig tokens.sml tiger.lex: mllex $/smlnj-lib.cm $/basis.cm $/ml-yacc-lib.cm
For record construction, yes. For record pattern matching, no.
If the field name and the variable you'd like to assign are the same, you don't have to mention them twice. You can also use an ellipsis (three dots) to stand in for as many fields as you'd like to leave out from the pattern match. For example, from assem.sml (homework 6):
fn OPER{assem, dst, src, jump=NONE} => speak(assem, dst, src, nil) | OPER{assem, dst, src, jump=SOME j} => speak(assem, dst, src, j) | LABEL{assem, ...} => assem | MOVE{assem, dst, src} => speak(assem, [dst], [src], nil)
Also, if you have a record value, each fields name prepended
by a hash may be used as a selector: #assem oper
.
For any mention of a record, SML/NJ needs to know exactly
what fields the record has. When you use ...
patterns or #
selectors, the type inference may not
be able to figure out what fields you've left out, and then
it will complain. Here's an example:
type point = { x: int, y: int, c: color } fun quadrant1 {x, y, ...} = x > 0 andalso y > 0
There are three simple ways to fix this:
fun quadrant1 {x, y, color} = x > 0 andalso y > 0
fun quadrant1 ({x, y, ...}: point) = x > 0 andalso y > 0
datatype
constructor:
datatype point = PT of { x: int, y: int, c: color } fun quadrant1 (PT {x, y, ...}) = x > 0 andalso y > 0
The latter two strategies also work with field selectors:
fun quadrant1 (p: point) = #x p > 0 andalso #y p > 0
The SML/NJ library (not the Standard Basis Library) provides a functor BinaryMapFn that constructs applicative (purely functional) maps, given an orderable key type. For example, to create mappings with string keys, you could do:
structure StringMap = BinaryMapFn(struct type ord_key = string val compare = String.compare end) val myMap = StringMap.empty val myMap2 = StringMap.insert (myMap, "hello", 4) fun whatIsHello m = case StringMap.find (m, "hello") of SOME i => i | NONE => raise NoGreetingHere
The resulting structure satisfies the ORD_MAP signature.
% echo 'compile "test.tig";' | sml sources.cm
Last updated 9 January 2008.