The library is organized in structures (see notes on modules).
We can list the contents of a structure using open.
Example:
Standard ML of New Jersey v110.59 [built: Thu Jun 8 17:56:38 2006]
- open Int;
[autoloading]
[library $SMLNJ-BASIS/basis.cm is stable]
[autoloading done]
opening Int
type int = ?.int
val precision : Int31.int option
val minInt : int option
val maxInt : int option
val toLarge : int -> IntInf.int
val fromLarge : IntInf.int -> int
val toInt : int -> Int31.int
val fromInt : Int31.int -> int
val ~ : int -> int
val + : int * int -> int
val - : int * int -> int
val * : int * int -> int
val div : int * int -> int
val mod : int * int -> int
val quot : int * int -> int
val rem : int * int -> int
val min : int * int -> int
val max : int * int -> int
val abs : int -> int
val sign : int -> Int31.int
val sameSign : int * int -> bool
val > : int * int -> bool
val >= : int * int -> bool
val < : int * int -> bool
val <= : int * int -> bool
val compare : int * int -> order
val toString : int -> string
val fromString : string -> int option
val scan : StringCvt.radix
-> (char,'a) StringCvt.reader -> (int,'a) StringCvt.reader
val fmt : StringCvt.radix -> int -> string
-
A warning: Opening a structure moves all definitions of a structure
into the current environment (so that you can write maxInt instead
of Int.maxInt). Sometimes this may lead to confusion. If you suspect
that something has gone wrong, the solution may be to restart the SML
system.
Let's take a look at Int.
- Int.maxInt; val it = SOME 1073741823 : int option - Int.minInt; val it = SOME ~1073741824 : int option -
Note that this is a smaller range than int in C (on a 32-bit machine)!
also try:
open Char;and
open Real;
Note that all structures implement
val compare : int * int -> order
where order is defined:
datatype order = LESS
| EQUAL
| GREATER
Try Int.compare(5,7).
Also, try
open String;
The signature for integers
(* integer.sig
*
* COPYRIGHT (c) 1995 AT&T Bell Laboratories.
*
*)
signature INTEGER =
sig
eqtype int
val precision : Int.int option
val minInt : int option
val maxInt : int option
val toLarge : int -> LargeInt.int
val fromLarge : LargeInt.int -> int
val toInt : int -> Int.int
val fromInt : Int.int -> int
val ~ : int -> int
val + : int * int -> int
val - : int * int -> int
val * : int * int -> int
val div : int * int -> int
val mod : int * int -> int
val quot : int * int -> int
val rem : int * int -> int
val min : (int * int) -> int
val max : (int * int) -> int
val abs : int -> int
val sign : int -> Int.int
val sameSign : (int * int) -> bool
val > : int * int -> bool
val >= : int * int -> bool
val < : int * int -> bool
val <= : int * int -> bool
val compare : (int * int) -> order
val toString : int -> string
val fromString : string -> int option
val scan :
StringCvt.radix -> (char, 'a) StringCvt.reader
-> (int, 'a) StringCvt.reader
val fmt : StringCvt.radix -> int -> string
end;
Structures that implement the interface:
IntInt32Int64FixedIntLargeIntWe have already seen Int.
Some experiments:
$ sml Standard ML of New Jersey v110.67 [built: Mon Dec 10 09:56:06 2007] - Int32.maxInt; [autoloading] [library $SMLNJ-BASIS/basis.cm is stable] [autoloading done] val it = SOME 2147483647 : Int32.int option - Int64.maxInt; [autoloading] [autoloading done] val it = SOME 9223372036854775807 : Int64.int option - FixedInt.maxInt; [autoloading] [autoloading done] val it = SOME 2147483647 : Int32.int option - LargeInt.maxInt; [autoloading] [autoloading done] val it = NONE : IntInf.int option -
Some arithmetic leads us to conclude that while regular Int is
stored in 31 bits, Int32 is 32 bit (same as the corresponding int
type in C on most implementations) and Int64 is 64 bit.
FixedInt is (on my machine) another name for Int32.
But why does LargeInt.maxInt return NONE?
An experiment may give a hint. First change a system variable to allow printing of big numbers:
- Control.Print.intinfDepth := 10000; val it = () : unit
Then create a large int equal to (almost) one million and start multiplying it to itself:
- LargeInt.fromInt 999999; [autoloading] [autoloading done] val it = 999999 : IntInf.int - LargeInt.*(it, it); val it = 999998000001 : IntInf.int - - LargeInt.*(it, it); val it = 999996000005999996000001 : IntInf.int - - LargeInt.*(it, it); val it = 9999920000279999440000699999440 00027999992000001 : IntInf.int - - LargeInt.*(it, it); val it = 99998400011999944000181999563200800798 8560012869988560008007995632001819999440 000119999984000001 : IntInf.int - - LargeInt.*(it, it); val it = 99996800049599504003595979862490618863 4154518271951264512110975745792492626871 4350342778810798242777514352526266257927 1097558451221195121051829663414490619179 8624035959995040000495999968000001 : IntInf.int - - LargeInt.*(it, it); val it = 999936[...]600001 : IntInf.int - - LargeInt.*(it, it); val it = 999872[...]000001 : IntInf.int - - LargeInt.*(it, it); val it = 999744[...]000001 : IntInf.int - - LargeInt.*(it, it); val it = 999488[...]000001 : IntInf.int - - LargeInt.*(it, it); val it = 998976[...]000001 : IntInf.int - - LargeInt.*(it, it); val it = 997954[...]50017# : IntInf.int - -
When the numbers become large, I only show the first six and last six
digits. The last number ends with "#" because it contains more than
10000 digits.
The structure LargeInt allows arbitrarily large integers. The
capacity of your computer sets limits on how big numbers it is
practical to compute with, but in principle the integers represented
by the LargeInt structure are unlimited.
Real, List, String
For those of you who know Java: They resemble the corresponding Java concepts.
The signature ORD_KEY
signature ORD_KEY =
sig
type ord_key
val compare : ord_key * ord_key -> order
end
We can easily define a structure that implements ORD_KEY, for
example:
structure StringKey =
struct
type ord_key = string
val compare = String.compare
end;
Let's first take a look at the signature ord-map
(* ordset-sig.sml
*
* COPYRIGHT (c) 1993 by AT&T Bell Laboratories. See COPYRIGHT file for details.
*
* Signature for a set of values with an order relation.
*)
signature ORD_SET =
sig
structure Key : ORD_KEY
type item = Key.ord_key
type set
val empty : set
(* The empty set *)
val singleton : item -> set
(* Create a singleton set *)
val fromList : item list -> set
(* create a set from a list of items *)
val add : set * item -> set
val add' : (item * set) -> set
(* Insert an item. *)
val addList : set * item list -> set
(* Insert items from list. *)
val delete : set * item -> set
(* Remove an item. Raise NotFound if not found. *)
val member : set * item -> bool
(* Return true if and only if item is an element in the set *)
val isEmpty : set -> bool
(* Return true if and only if the set is empty *)
val equal : (set * set) -> bool
(* Return true if and only if the two sets are equal *)
val compare : (set * set) -> order
(* does a lexical comparison of two sets *)
val isSubset : (set * set) -> bool
(* Return true if and only if the first set is a subset of the second *)
val numItems : set -> int
(* Return the number of items in the table *)
val listItems : set -> item list
(* Return an ordered list of the items in the set *)
val union : set * set -> set
(* Union *)
val intersection : set * set -> set
(* Intersection *)
val difference : set * set -> set
(* Difference *)
val map : (item -> item) -> set -> set
(* Create a new set by applying a map function to the elements
* of the set.
*)
val app : (item -> unit) -> set -> unit
(* Apply a function to the entries of the set
* in increasing order
*)
val foldl : (item * 'b -> 'b) -> 'b -> set -> 'b
(* Apply a folding function to the entries of the set
* in increasing order
*)
val foldr : (item * 'b -> 'b) -> 'b -> set -> 'b
(* Apply a folding function to the entries of the set
* in decreasing order
*)
val partition : (item -> bool) -> set -> (set * set)
val filter : (item -> bool) -> set -> set
val exists : (item -> bool) -> set -> bool
val find : (item -> bool) -> set -> item option
end (* ORD_SET *)
A lot of operations. You find (for example): create an empty set, add an element to a set (the set is not modified; a new one is created), check if an element is a member, check if one set is a subset of another, and create a list of all elements of a set.
But ORD_SET is just an interface; we need an implementation to be
able to create sets.
The functor
RedBlackSetFn(K:ORD_KEY) : ORD_SETgives us that.
For example;
structure SSet = RedBlackSetFn(StringKey);creates an ordered set that uses red-black trees in the inderlying implementation and has strings for keys.
- SSet.empty; val it = - : SSet.set - SSet.add(it, "foo"); val it = - : SSet.set - SSet.add(it, "bar"); val it = - : SSet.set - SSet.listItems(it); val it = ["bar","foo"] : SSet.item list
The signature ORD_MAP is similar:
(* ord-map-sig.sml
*
* COPYRIGHT (c) 1996 by AT&T Research. See COPYRIGHT file for details.
*
* Abstract signature of an applicative-style finite maps (dictionaries)
* structure over ordered monomorphic keys.
*)
signature ORD_MAP =
sig
structure Key : ORD_KEY
type 'a map
val empty : 'a map
(* The empty map *)
val isEmpty : 'a map -> bool
(* Return true if and only if the map is empty *)
val singleton : (Key.ord_key * 'a) -> 'a map
(* return the specified singleton map *)
val insert : 'a map * Key.ord_key * 'a -> 'a map
val insert' : ((Key.ord_key * 'a) * 'a map) -> 'a map
(* Insert an item. *)
val find : 'a map * Key.ord_key -> 'a option
(* Look for an item, return NONE if the item doesn't exist *)
val lookup : 'a map * Key.ord_key -> 'a
(* look for an item, raise the NotFound exception if it doesn't exist *)
val inDomain : ('a map * Key.ord_key) -> bool
(* return true, if the key is in the domain of the map *)
val remove : 'a map * Key.ord_key -> 'a map * 'a
(* Remove an item, returning new map and value removed.
* Raises LibBase.NotFound if not found.
*)
val first : 'a map -> 'a option
val firsti : 'a map -> (Key.ord_key * 'a) option
(* return the first item in the map (or NONE if it is empty) *)
val numItems : 'a map -> int
(* Return the number of items in the map *)
val listItems : 'a map -> 'a list
val listItemsi : 'a map -> (Key.ord_key * 'a) list
(* Return an ordered list of the items (and their keys) in the map. *)
val listKeys : 'a map -> Key.ord_key list
(* return an ordered list of the keys in the map. *)
val collate : ('a * 'a -> order) -> ('a map * 'a map) -> order
(* given an ordering on the map's range, return an ordering
* on the map.
*)
val unionWith : ('a * 'a -> 'a) -> ('a map * 'a map) -> 'a map
val unionWithi : (Key.ord_key * 'a * 'a -> 'a) -> ('a map * 'a map) -> 'a map
(* return a map whose domain is the union of the domains of the two input
* maps, using the supplied function to define the map on elements that
* are in both domains.
*)
val intersectWith : ('a * 'b -> 'c) -> ('a map * 'b map) -> 'c map
val intersectWithi : (Key.ord_key * 'a * 'b -> 'c) -> ('a map * 'b map) -> 'c map
(* return a map whose domain is the intersection of the domains of the
* two input maps, using the supplied function to define the range.
*)
val mergeWith : ('a option * 'b option -> 'c option)
-> ('a map * 'b map) -> 'c map
val mergeWithi : (Key.ord_key * 'a option * 'b option -> 'c option)
-> ('a map * 'b map) -> 'c map
(* merge two maps using the given function to control the merge. For
* each key k in the union of the two maps domains, the function
* is applied to the image of the key under the map. If the function
* returns SOME y, then (k, y) is added to the resulting map.
*)
val app : ('a -> unit) -> 'a map -> unit
val appi : ((Key.ord_key * 'a) -> unit) -> 'a map -> unit
(* Apply a function to the entries of the map in map order. *)
val map : ('a -> 'b) -> 'a map -> 'b map
val mapi : (Key.ord_key * 'a -> 'b) -> 'a map -> 'b map
(* Create a new map by applying a map function to the
* name/value pairs in the map.
*)
val foldl : ('a * 'b -> 'b) -> 'b -> 'a map -> 'b
val foldli : (Key.ord_key * 'a * 'b -> 'b) -> 'b -> 'a map -> 'b
(* Apply a folding function to the entries of the map
* in increasing map order.
*)
val foldr : ('a * 'b -> 'b) -> 'b -> 'a map -> 'b
val foldri : (Key.ord_key * 'a * 'b -> 'b) -> 'b -> 'a map -> 'b
(* Apply a folding function to the entries of the map
* in decreasing map order.
*)
val filter : ('a -> bool) -> 'a map -> 'a map
val filteri : (Key.ord_key * 'a -> bool) -> 'a map -> 'a map
(* Filter out those elements of the map that do not satisfy the
* predicate. The filtering is done in increasing map order.
*)
val mapPartial : ('a -> 'b option) -> 'a map -> 'b map
val mapPartiali : (Key.ord_key * 'a -> 'b option) -> 'a map -> 'b map
(* map a partial function over the elements of a map in increasing
* map order.
*)
end (* ORD_MAP *)
There is a similar functor RedBlackMapFn that implements ORD_MAP.
- structure SMap = RedBlackMapFn(StringKey);
structure SMap : ORD_MAP?
- SMap.empty;
val it = - : 'a SMap.map
- SMap.insert(it, "foo", 37);
val it = - : int SMap.map
- SMap.insert(it, "bar", 42);
val it = - : int SMap.map
- val q = it;
val q = - : int SMap.map
- SMap.find(it, "foo");
val it = SOME 37 : int option
- SMap.find(q, "FOO");
val it = NONE : int option
- SMap.listItemsi(q);
val it = [("bar",42),("foo",37)] : (StringKey.ord_key * int) list