V10/cmd/sml/doc/help
Help: A few hints for beginning users of SML of NJ
1. running Standard ML
Type "sml". This puts you into the interactive system. The top level
prompt is "- ", and the secondary prompt (printed when input is
incomplete) is "= ". If you get the secondary prompt when you don't
expect it, typing ";<return>" will often complete your input, or type
your interrupt character (e.g. ^C) to cancel your input and return you
to top level.
If "sml" doesn't work, ask where sml has been installed on your machine
and use the appropriate path name or redefine your PATH environment variable.
2. interactive input
Input to the top level interpreter (i.e. declarations and expressions)
must be terminated by a semicolon (and carriage return) before the
system will evaluate it. The system then prints out a response
indicating the effect of the evaluation. Expressions are treated as
implicit declarations of a standard variable "it". For example,
- 3; <return> <- user input after prompt
val it = 3 : int <- system response
This means that the value of the last top level expression evaluated
can be referred to using the variable "it".
2. changing the prompts
The primary and secondary prompt strings are the contents of the
references
System.Control.primaryPrompt
System.Control.secondaryPrompt
These can be redefined by assignment, e.g.:
- System.Control.secondaryPrompt := "(**)";
3. interrupting parsing or computation
Typing your interrupt character should interrupt the compiler and
return you to top level, unless some function is catching the
Interrupt exception (a dangerous thing to do).
4. exiting the interactive system
Typing ^D (EOF) at top level will cause an exit to the shell (or the
parent process from which sml was run).
5. loading ML source text from a file
The operator use: string->unit interprets its argument as a Unix file
name relative to sml's current directory and loads the text from that
file as though it had been typed in. "use" should normally be
executed at top level, but the loaded files can also contain calls of
use to recursively load other files. It is a bad idea to call use
within an expression or declaration, because the effects are not
well-defined.
6. saving an image of the system
Use the function exportML: string->bool to dump an image of the
current sml system including the environment that you have built. The
argument is the path name of the image file that is created. The
result false is returned in the original system, while in the saved
image the value returned is true. The call of exportML can be
embedded in an expression which will continue evaluation (e.g. to
print a message) in both the original system and in the image when it
is run, and its effect can depend on the result of the exportML call.
For example:
if exportML("saved")
then print "this is the saved image\n"
else print "this is the original process\n"
The saved image file is an executable binary, and can be run by typing
the file name as a command to the shell. (Access to command-line
arguments and Unix environment variables when running the saved image
may be accomplished by System.argv and System.environ.)
7. executing System commands and changing directories
The function system : string->unit spawns a process to execute its argument
string as a shell command. Thus to find out what the current directory is
within sml you can evaluate the expression
system "pwd";
which will cause the current directory to be printed out (there is no
way at the moment to return the current directory as a string). To
change the current working directory of sml use the function
cd :string -> unit, whose argument should be a path name denoting a
directory.
8. error messages
The error messages produced by the compiler are not always as helpful
as they should be, and there are often too many of them.
The compiler attempts to recover from syntactic and type errors so
that it can detect as many errors as possible during a compilation.
Unfortunately, it is not very graceful in recovery, and the process
can cause numerous spurious secondary error messages.
When compiling files, the error messages include a line number. For
simple syntactic errors this line number is often accurate or off by
just one line. For other classes of errors, including type errors,
the line number may not be very useful, since it will often just
indicate the end of the declaration containing the error, and this
declaration can be quite large.
There are a number of different forms of type error message, and it
may require some practice before you become adept at interpreting
them. The most common form indicates a mismatch between the type of a
function (or operator) and its argument (or operand). A
representation of the offending expression is usually included, but
this is an image of the internal abstract syntax for the expression
and may differ significantly from the original source code. For
instance, an "if...then...else..." expression is represented
internally as a case expression over a boolean value:
"case ... of true => ... | false => ...".
9. useful system flags
There are a number of useful system flags and variables, which are
found in the structure System.Control and its substructures. The
primary and secondary prompt variable have already been mentioned;
here are some more:
Printing: System.Control.Print. ...
printDepth : int ref
controls depth to which complex values and syntax trees are printed
(default 5)
stringDepth : int ref
controls how much of a long string will be printed (default 70)
signatures : bool ref
when true, signatures, and the signatures of structures, will be
printed when these are defined at top level (default true)
Garbage collection messages:
System.Control.Runtime.gcmessages: int ref
when 0, no messages are printed
when 1, only major collections are reported (the default)
when 2, major collections and heap resizings are reported
when 3, minor and major collections and heap resizings are reported
Memory use:
System.Control.Runtime.ratio : int ref
determines the desired ratio between size of live data and total heap
size. Default is 5, and 3 is the smallest acceptable value. A higher
ratio causes more aggressive use of memory (up to the softmax bound).
System.Control.Runtime.softmax : int ref
suggested ceiling on heap size, in bytes. Heap size will not grow
beyond this value except to maintain the "minimum" ratio of 3. Actually,
when hard limits are reached (e.g. as determined by limit datasize), the
system can continue to run as long as the actual ratio is greater than 2.
A good value for softmax is one that reflects the amount of physical
(not virtual) memory that is expected to be available for the sml process,
for instance, 5000000 (5MB) might be appropriate on an 8MB Sun 3.
10. Timing
The structure System.Timer, which has the signature
signature TIMER =
sig
datatype time = TIME of {sec : int, usec : int}
type timer
val start_timer : unit -> timer
val check_timer : timer -> time
val makestring : time -> string
val add_time : time * time -> time
end
provides basic facilities for timing your code. Here is how a typical
timing function could be implemented:
fun timeit (f: unit->'a) =
let open System.Timer
val start = start_timer()
val result = f()
in print(makestring(check_timer(start)));
print "\n";
result
end;
11. Profiling
See the file doc/profiling for instructions on using the built-in
profiling facilities.
12. Basic ML environment
Look at the files src/boot/perv.sig and src/boot/system.sig
for signatures that specify what is available in the basic environment.