CS312 FAQ

List of topics

Getting started with SML/NJ

After installing the course software, you should be able to start it.  On Windows, SML puts a shortcut in the start menu -- you can use this if you like icons.  A more common, and useful, way of starting SML/NJ is at the command prompt which works for both Unix and Windows. Simply type sml at the command prompt:
C:\>sml
Standard ML of New Jersey, Version 110.0.7, September 28, 2000 [CM&CMB]
-

The directory from which you start SML is the working directory.  When compiling files for problem sets, the working directory needs to be the directory in which the .sml and .cm files for the project reside.  The other way to start SML/NJ is in a subshell of Emacs.  To do this, when in sml-mode type M-x sml -- this starts the compiler.  To switch to the SML/NJ interactive loop type C-c C-s.

The prompt in the interactive loop is -.  If you start entering an expression and go to the next line, SML/NJ shows the = sign as the prompt.  This means SML is waiting to evaluate the expression until you have finished writing the whole expression.  SML knows to evaluate an expression when it sees a semi-colon.  Consider the following:

- String.map Char.toUpper
=            "The quick brown fox jumps over the lazy dog.";
val it = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG." : string
-

To exit the SML interactive loop, you simply need to send the end-of-file character.  On Windows, the end-of-file character is CTRL-Z.  On Unix, this is CTRL-D.  Since C-z minimizes Emacs, to close an SML subshell you only need to terminate the process first by entering (C-c C-d) in the interactive SML session and then close the buffer (C-x k).

Equality is not defined for all values

Programming languages have many notions of equality.  The designers of SML wanted to keep the language design clean and lend as much power as possible to the compiler to do optimizations.  Thus, SML does not have pointer equality tests as Java and C have.  Another surprising decision is that equality is not readily defined for real values; that is, = is not defined for real values.

In fact, you'll find that = and <> are special functions not defined in any module of the basis library.  These functions only work on some values where determining equality is decisive and inarguable.  Real values in SML are based on the IEEE floating point specification, which includes values such as NaN.  As computers only have finite storage, it is impossible to always represent every number.  Indeed cancellation error can occur, consider "1.0 + 0.000000000001".  This evaluates to "1.0".  The best way to determine equality is using <= and >= constraining the value to some delta range.  Of course, if you want to, Real.== and Real.!= are available for equality tests.

Converting between values of different types

Unlike Java or C++, SML does not implicitly convert values when it is convenient.  This means integers aren't implicitly converted to real values, characters to strings, or numbers to strings.  SML requires the programmer to explicitly convert between types using functions provided in the basis library.  Here are the most frequently used conversion functions:
Int.toString          Real.round
Int.fromString        Real.fromInt
Real.toString         Char.ord
Real.fromString       Char.chr
Real.floor            Char.toString
Real.ceil             Char.fromString
Real.trunc            String.str

Several of these functions are included in the top-level, including ord, chr, and str.  You can look up the exact semantics of each function in the basis library documentation.

Understanding error messages

Compile time errors are something you are likely to see often.  Unfortunately, the error messages aren't always that clear.  Here is an example of an error message:
general.sml:15.3-15.19 Error: operator and operand don't agree [literal]
  operator domain: int * int
  operand:         int * real
  in expression:
    40 + 2.0

Let's start from the beginning:

Here is another common error message:

general.sml:15.26 Error: syntax error: inserting  IN

Clearly, this is a syntax error.  It is suggesting that inserting the keyword in will fix the syntax error.  Undoubtedly, you will encounter an indecipherable error message.  Fortunately, there is a list of error messages and what they mean.

Using option types to create "nullable" values

Java has two categories of values: primitive and reference types.  Java reference types are nullable, whereas primitive types are not.  No value in SML is by itself nullable; however, it is possible to make any value nullable by using the polymorphic option type:
datatype 'a option = NONE | SOME of 'a

Thus you will note that values in SML are more flexible than those of Java.  A good programmer always knows to check for null values when programming in Java or C++.  The option type has the advantage that the SML type system forces you to check for NONE values.

Understanding the garbage collection messages

You're likely to see a lot of garbage collection messages, and if you're curious what they really mean you have to understand generational garbage collection.  Later in the course we'll discuss a few garbage collection techniques, and you will actually implement one of them.  Nevertheless, understanding the garbage collection messages can say a lot about the programs you write.  Consider the following:
GC #8.64.65.66.69.364:   (210 ms)
    5  4  3  2  1   0       time

The top line is an example of a garbage collection message.  Listed below it is the generations.  Garbage collection messages only appear when a collection occurs in generations one and above.  The numbers listed are the number of garbage collections that have occurred.  For instance, in the example above, there have been 8 collections in the 5th generation.  Collecting generation one and above are called major collections.  Collecting for generation zero is called a minor collection.  More important to you is the time listed on the right.  In this case, it took 210 milliseconds to complete the garbage collection.

Another common question about garbage collection messages is just how to turn them off.  SML/NJ provides for turning off the messages by evaluating the following:

SMLofNJ.Internals.GC.messages false

Passing false to the function turns the messages off.  Passing true to this function turns the messages on.

Avoiding abbreviations in the output


When the system gives the result of an evaluation, it may abbreviate
with the character ``#'' part of the representation of a data structure.
For instance:

- datatype bintree = emp | nod of bintree * int * bintree;
datatype bintree = emp | nod of bintree * int * bintree
- nod(nod(nod(emp,2,emp),3,emp),1,nod(nod(emp,4,emp),5,emp));
val it = nod (nod (nod #,3,emp),1,nod (nod #,5,emp)) : bintree

In order to avoid this, you can use the "print switches" OF SML, which are:

  Compiler.Control.Print.printDepth       (for data structures)
  Compiler.Control.Print.printLength      (for lists)
  Compiler.Control.Print.stringDepth      (for strings)

You should set these at the prompt:

- Compiler.Control.Print.printDepth := 1000;
val it = () : unit
- nod(nod(nod(emp,2,emp),3,emp),1,nod(nod(emp,4,emp),5,emp));
val it = nod (nod (nod (emp,2,emp),3,emp),1,nod (nod (emp,4,emp),
5,emp)) : bintree

Windows does a BSOD when starting SML/NJ in Emacs

If your computer suddenly comes up with the blue screen of death when starting SML/NJ in Emacs (aka M-x sml), then you've got a problem.  Luckily, there's a solution.  The crash is caused by an interference between Norton Antivirus and Emacs spawning a subprocess.  You should disable virus protection programs when starting the SML compiler in Emacs.

SML/NJ can't find "sources.cm"

SML/NJ must be started with the proper current directory (the directory containing your project files). There are several ways to do this:
  1. Open a DOS prompt (or Unix shell), "cd" to the correct directory, and then start SML.
  2. Make a shortcut to SML, right-click and open Properties, then put in the appropriate working directory.
  3. Do OS.FileSys.chDir "foo" once you've started SML, specifying either an absolute path or a relative path.
  4. Open a file in Emacs located in the same directory as your sources.cm file before starting SML -- opening up sources.cm itself will work, if that's the only thing not in a subdirectory.

Finding more information