PostScript documentation for sml is also available. Documentation is available for the base, or standard, environment, the system-dependent library, and for sml's extended library. There's even an index. Be careful printing; some of this documentation is very long.
Here's what a typical session looks like
ammons@diamond-joe:cs538> eXene eXene -- version 0.4 -- February 11, 1993 Concurrent ML -- version 0.9.8 -- February 1, 1993 Standard ML of New Jersey, Version 0.93, February 15, 1993 val it = () : unit - output (std_out, "Hello, world.\n"); Hello, world. val it = () : unit - ammons@diamond-joe:cs538>I typed the stuff after the - prompts. The rest is output from the compiler. I got out of eXene by pressing Ctrl-D.
There is a later version of sml, sml-1.08, installed under /unsup. Don't use this version; it is unstable and somewhat incompatible with earlier versions of sml.
Typing expressions at the prompt is a great way to test code and develop small functions, but if you're writing something larger, you'll probably want to put it in a file and import the file. Say that hello.sml is
output (std_out, "Hello, world.\n");Then, the following session is equivalent to the session above:
ammons@diamond-joe:cs538> eXene eXene -- version 0.4 -- February 11, 1993 Concurrent ML -- version 0.9.8 -- February 1, 1993 Standard ML of New Jersey, Version 0.93, February 15, 1993 val it = () : unit - use "hello.sml"; [opening hello.sml] Hello, world. val it = () : unit val it = () : unit - ammons@diamond-joe:cs538>The compiler evaluated the expression from hello.sml just as if it had been typed at the prompt. This example only had one expression in the file, but the file may contain several expressions. The expressions are evaluated in the order in which they appear in the file.
ammons@diamond-joe:cs538> eXene eXene -- version 0.4 -- February 11, 1993 Concurrent ML -- version 0.9.8 -- February 1, 1993 Standard ML of New Jersey, Version 0.93, February 15, 1993 val it = () : unit - fun hello (argv, environ) = output (std_out, "Hello, world.\n"); val hello = fn : 'a * 'b -> unit - exportFn ("hello", hello); [Major collection... 15% used (692596/4413684), 284 msec] [Decreasing heap to 3397k] [Major collection... 44% used (310940/695088), 83 msec] [Decreasing heap to 1521k] ammons@diamond-joe:cs538> ls -l hello -rwxr-xr-x 1 ammons 26014 417436 Apr 5 06:54 hello ammons@diamond-joe:cs538> ./hello Hello, world. ammons@diamond-joe:cs538>The function exportFn (s, f) writes an executable s that starts by executing f. f must take a tuple of 2 lists of strings. The first list is the list of command line arguments and the second list is a list of environment variables. Here's a program which actually uses the command line arguments:
ammons@diamond-joe:cs538> eXene eXene -- version 0.4 -- February 11, 1993 Concurrent ML -- version 0.9.8 -- February 1, 1993 Standard ML of New Jersey, Version 0.93, February 15, 1993 val it = () : unit - fun paste (nil) = "\n" = | paste (s::nil) = s ^ paste (nil) = | paste (s::tl) = s ^ " " ^ paste (tl); val paste = fn : string list -> string - fun echo (argv, environ) = output (std_out, paste argv); val echo = fn : string list * 'a -> unit - exportFn ("echo", echo); [Major collection... 8% used (358796/4429500), 183 msec] [Decreasing heap to 1753k] [Major collection... 99% used (358908/358988), 150 msec] ammons@diamond-joe:cs538> ./echo a bunch of args ./echo a bunch of args ammons@diamond-joe:cs538>Notice that the first element of argv is the name of the program, just like in C.
There's no reason to use exportFn before you're ready to produce your final executable. It's much more convenient to test your program by evaluating expressions at the sml prompt.
ammons@diamond-joe:cs538> eXene eXene -- version 0.4 -- February 11, 1993 Concurrent ML -- version 0.9.8 -- February 1, 1993 Standard ML of New Jersey, Version 0.93, February 15, 1993 val it = () : unit - open StringCvt; open StringCvt exception Convert = Convert val strToInt = fn : radix -> string * int -> int * int val atoi = fn : string -> int val xatoi = fn : string -> int val oatoi = fn : string -> int val strToReal = fn : string * int -> real * int val atof = fn : string -> real val strToBool = fn : string * int -> bool * int val atob = fn : string -> bool - atoi "14"; val it = 14 : int -I opened StringCvt so I could refer to StringCvt.atoi simply as atoi.
These functions are documented in /s/sml/doc/sml/manual/LIB.ps.
- open System.Timer; (* for the time datatype *) ... - open System.Unsafe.CInterface; (* for gettimeofday *) ... val gettimeofday = fn : unit -> time - open Random; val random = fn : real -> real val mkRandom = fn : real -> unit -> real val norm = fn : real -> real val range = fn : int * int -> real -> int - gettimeofday (); val it = TIME {sec=828719866,usec=910014} : time - val TIME { sec=s, ... } = gettimeofday (); val s = 828719870 : int - val gen = mkRandom (real s); val gen = fn : unit -> real - gen (); val it = 1863404295.0 : real - gen (); val it = 1481961864.0 : real - val tosix = range (1, 6); val tosix = fn : real -> int - val roll = tosix o gen; val roll = fn : unit -> int - roll (); val it = 6 : int - roll (); val it = 1 : int - roll (); val it = 2 : intAs you can see, roll () is not a pure function, because, given identical input, it doesn't always return identical values. Despite this, programs that use Random or gettimeofday are still eligible for the functional programming bonus.
These functions are documented in /s/sml/doc/sml/manual/LIB.ps.
- open Array; open Array exception Subscript = Subscript val tabulate = fn : int * (int -> '1a) -> '1a array val length =As the example demonstrates, you look up entries in the array with sub and change the value of an entry with update.: 'a array -> int val sub = : 'a array * int -> 'a val arrayoflist = fn : '1a list -> '1a array val array = fn : int * '1a -> '1a array exception Size = Size val update = : 'a array * int * 'a -> unit - val iarray = array (100, 4); val iarray = [|4,4,4,4,4,4,4,4,4,4,4,4,...|] : int array - val rarray = arrayoflist ([1.3,3.14,2.7]); val rarray = [|1.3,3.14,2.7|] : real array - sub (iarray,12); val it = 4 : int - sub (iarray, 1000); uncaught exception Subscript - sub (rarray, 1); val it = 3.14 : real - update (rarray, 1, ~3.14159); val it = () : unit - sub (rarray, 1); val it = ~3.14159 : real - length rarray; val it = 3 : int - length iarray; val it = 100 : int -
If you are going for the functional programming bonus and need a constant-time indexable sequence of values, take a look at the Vector structure. That structure contains functions to create read-only "arrays". You specify the initial contents, which cannot subsequently be changed.
These functions are documented in /s/sml/doc/sml/manual/BASE.ps.