Cse321, Programming Languages and Compilers
Standard ML
• In this course we will use an implementation of the
language Standard ML
• Notes by Riccardo Pucella, about programming in ML
• http://www.cs.cornell.edu/riccardo/smlnj.html
• The SML/NJ Homepage has lots of useful
information: http://www.smlnj.org//
• You can get a version to install on your own machine
there.
I will use the version 110.57 of SML. Earlier versions probably will work
as well. I don’t foresee any problems with other versions, but if you
want to use the identical version that I use in class then this is the
one.
7/13/2017
1
Cse321, Programming Languages and Compilers
Characteristics of SML
• Applicative style
– input output description of problem.
• First class functions
– pass as parameters
– return as value of a function
– store in data-structures
• Less Importantly:
– Automatic memory management (G.C. no new or malloc)
– Use of a strong type system which uses type inference, i.e. no
declarations but still strongly typed.
7/13/2017
2
Cse321, Programming Languages and Compilers
Syntactic Elements
• Identifiers start with a letter followed by digits or
other letters or primes or underscores.
– Valid Examples: a a3
– Invalid Examples: 12A
a’b aF
• Identifiers can also be constructed with a sequence
of operators like: !@#$%^&*+~
• Reserved words include
–
–
7/13/2017
fun val datatype if then else
if of let in end type
3
Cse321, Programming Languages and Compilers
Interacting
• The normal style for interaction is to start SML, and
then type definitions into the window.
• Types of commands
– 4 + 5;
– val x = 34;
– fun f x = x + 1;
• Here are two commands you might find useful.
val pwd = OS.FileSys.getDir;
val cd = OS.FileSys.chDir;
• To load a file that has a sml program type
Use “file.sml”;
7/13/2017
4
Cse321, Programming Languages and Compilers
The SML Read-Typecheck-Eval-Print Loop
Standard ML of New Jersey v110.57 [built: Mon Nov 21 21:46:28 2005]
- 3+5;
val it = 8 : int
Note the semicolon when
- print "Hi there\n";
you’re ready to evaluate.
Hi there
Otherwise commands can
val it = () : unit
spread across several lines.
- val x = 22;
val x = 22 : int
- x+ 5;
val it = 27 : int
-val pwd = OS.FileSys.getDir;
-val pwd = fn : unit -> string
- val cd = OS.FileSys.chDir;
val cd = fn : string -> unit
7/13/2017
5
Cse321, Programming Languages and Compilers
Evaluation vs. Declaration
evaluation
- 5;
val it = 5 : int
- 3+4;
val it = 7 : int
declaration
- val it = 7 : int
- val tim = 5 : int
evaluation
- tim + 7;
val it = 12 : int
declaration
- fun plusone x = x + 1;
val plusone = fn : int -> int
7/13/2017
6
Cse321, Programming Languages and Compilers
Bindings and environments, and scope:
val x = 12;
fun f x = x + 2;
fun g y = x + 2;
• fun bindings are just like val bindings
val f = (fn x => x + 2);
• But NOT RECURSIVE PROGRAMS! why?
fun plus x y = if x = 0 then y
else 1 + (plus (x-1) y);
val rec plus = fn x => fn y =>
if x = 0 then y
else 1 + (plus (x-1) y);
7/13/2017
7
Cse321, Programming Languages and Compilers
Functions
• Functions are usually defined in Files and loaded
into to SML. Example:
–
use
“lect01.sml”
• Functions on numbers
– Type of numbers: Int and Real
– Conversion functions: floor, ceiling, trunc, round
• Functions on Booleans
– Relational operators
<
>
<=
>=
– Combinators
andalso orelse
==
!=
• Examples
- 5 > 7
false
- 1==4
false
7/13/2017
8
Cse321, Programming Languages and Compilers
Finding type of functions
- length
val it =
- op @;
val it =
- rev;
val it =
- op +;
val it =
7/13/2017
fn : 'a list -> int
fn : 'a list * 'a list -> 'a list
fn : 'a list -> 'a list
fn : int * int -> int
9
Cse321, Programming Languages and Compilers
Functions
• Defined by writing equations (sometimes more than 1)
• By Declaration: fun plusone x = x+1;
• By Lambda expression: fn x => x + 1
–
These are anonymous functions, and are probably new to you. Don’t let
them scare you.
• Application by juxtaposition (no parenthesis needed)
•
plusone 8
•
(fn x => x + 1) 8
• Functions of more than 1 argument:
• tuples
• currying
7/13/2017
10
Cse321, Programming Languages and Compilers
Multi Argument functions: Tuples
• fun evenprod (x,y) = even(x * y);
• Conditional Expressions: If
• fun minpair (x,y) = if x < y then x else y;
7/13/2017
11
Cse321, Programming Languages and Compilers
Multi Argument functions: By Currying
fun f a b c = a + b + c + 1;
• has type
val f = fn : int -> int -> int -> int
• READ AS: int -> (int -> (int -> int))
• Be sure you understand the difference between the
two styles.
• fun evenprod (x,y) = even(x * y);
–
(int * int) -> bool
• fun evenprod’ x y = even(x * y);
–
7/13/2017
int -> int -> bool
12
Cse321, Programming Languages and Compilers
Pattern Matching Definitions:
fun
|
|
|
and
and
and
and
true false = false
true true = true
false false = false
false true = false;
Note that “and”
has more than 1
equation.
• (ORDER MATTERS)
• Variables in Patterns:
fun and true true = true
| and x y = false
7/13/2017
13
Cse321, Programming Languages and Compilers
Rules for patterns:
• Patterns has only Constructors, (true, false, :: )
variables (x, y, z) , and constants (3, “red”).
• All the patterns (on the left) should have compatible
types
• The cases should be exhaustive
• There should be no ambiguity as to which case
applies. (Ordering fixes ambiguity if there is any)
7/13/2017
14
Cse321, Programming Languages and Compilers
Lists in ML
• Constant lists
• [3,6,8]
• ["red", "yellow", ""]
• []
7/13/2017
15
Cse321, Programming Languages and Compilers
Construction of lists
• The Empty List
[]
• The "Cons" (op :: ) Constructor
4::[3,7];
val it = [4,3,7] : int list
• Concatenation
[3,4] @ [6,7,8]
val it = [3,4,6,7,8] : int list
7/13/2017
16
Cse321, Programming Languages and Compilers
Taking Lists Apart
? hd [1,2,3]
1
? tl [1,2,3]
[2, 3]
? List.take (2,[1,2,3])
[1,2]
? List.drop (2,[1,2,3])
[3]
7/13/2017
17
Cse321, Programming Languages and Compilers
Libraries
• There are lots of predefined types and
functions in SML when it starts up.
• You can find out about them at:
http://www.smlnj.org//basis/pages/top-level-chapter.html
• Many more can be found in the other
libraries.
– http://www.standardml.org/Basis/manpages.html
• Libraries are encapsulated in Structures
which are classified by Signatures (a list of
what is in the structure).
7/13/2017
18
Cse321, Programming Languages and Compilers
Peeking inside a Structure
• To see what is inside a Structure you can open it.
• This is somewhat of a hack, but it is useful.
Standard ML of New Jersey v110.57 [built: Mon Nov 21 21:46:28 2005]
- signature S = INTEGER;
signature INTEGER =
sig
eqtype int
val precision : Int31.int option
val minInt : int option
val maxInt : int option
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
. . .
end
7/13/2017
19
Cse321, Programming Languages and Compilers
In Class Exercise 1
•
•
•
•
Define prefix and lastone in terms of head tail and reverse.
First make a file “S01code.sml”
Start sml
fun lastone x = hd (rev x)
fun prefix x = rev (tl (rev x))
Change directory to
where the file resides
• Load the file ( use “S01code.sml” )
• Test the function
Standard ML of New Jersey v110.57 - K;
- val cd = OS.FileSys.chDir;
val cd = fn : string -> unit
- cd "D:/work/sheard/courses/PsuCs321/web/notes";
- use "S01code.sml";
[opening S01code.sml]
val lastone = fn : 'a list -> 'a
val prefix = fn : 'a list -> 'a list
val it = () : unit
- lastone [1,2,3,4];
val it = 4 : int
7/13/2017
20
Cse321, Programming Languages and Compilers
In Class Exercise 2
• define map and filter functions
– mymap f [1,2,3]
=
[f 1, f 2, f 3]
– filter even [1,2,3,4,5]
=
[2,4]
fun mymap f [] = []
| mymap f (x::xs) = (f x)::(mymap f xs);
fun filter p [] = []
| filter p (x::xs) =
if (p x) then x::(filter p xs) else (filter p xs);
• Sample Session
- mymap plusone [2,3,4]
[3, 4, 5]
- myfilter even [1,2,3,4,5,6]
[2, 4, 6]
7/13/2017
21
Cse321, Programming Languages and Compilers
Case expressions
Keyword
of
val ex1 =
case
[1,2,3]
of
Clauses can
Clauses
span multiple
separated
lines
[] => 0
by “|”
| (1::xs) => if null xs
then 1
else 2
| (x::xs) => 3;
7/13/2017
The semicolon ends
the “val ex1 = ”
declaration not the
case exp.
22
Cse321, Programming Languages and Compilers
Using case in fun definition
• The case expression uses patterns
fun length(y) =
case y of
[] => 0
| (x :: xs) => 1 + (length xs)
• In the pattern: (x :: xs)
– x, stands for the hd(y)
– xs, stands for the tl(y)
7/13/2017
23
Cse321, Programming Languages and Compilers
More about patterns
• Patterns can be nested
• Patterns can have wild-cards
fun double y =
case y of
(a :: (b :: [])) => true
| _ => false
These features can be
used in “fun”
declarations with
multiple clauses as
well as in “case”
expressions!
• Special syntax for list Patterns
fun exactlytwo x =
Case x of
[] => false
| [x] => false
| [x,y] => true
| (x:xs) => false;
7/13/2017
24
Cse321, Programming Languages and Compilers
Let expressions
• Let expressions allow programmers to make local
declaration for both values and functions.
Multiple declarations allowed,
both “val” and “fun”, no
separators necessary
val ex2 =
let val x = 34
fun f x = x - 3
in f x - 4 end;
The scope of the new
declarations is the
expression between the key
words “in” and “end”
7/13/2017
25
Cse321, Programming Languages and Compilers
Exceptions
exception Error of string;
A new exception is declared, it carries a
string as error information. Exceptions can
carry any kind of data.
fun error s = raise (Error s);
Exceptions can be raised, to
short-circuit normal
evaluation.
fun ex3 b =
(if b then error "true branch"
else "false branch")
handle
Error message => message
Keyword
| other => raise other;
handle
A handler, like a “case” has multiple clauses, each can handle
a different kind of error. Note “|” separating clauses.
7/13/2017
Main
computation
returns a string
Handler also
returns a string
26
Cse321, Programming Languages and Compilers
Syntax of “case” vs “handle”
• “case” is before the computation being analyzed
case (revonto (g x) 4) of
[] => true
| (x:xs) => false
• “handle” is after the computation that might fail
(compute (g y) (length zs))
handle
Error s => g s
| BadLevel n => n+1
| other => raise other
7/13/2017
27
Cse321, Programming Languages and Compilers
Review
• Case, let, and exceptions are rich constructs in ML.
• Case allows pattern matching without defining a new
function.
• Let allows us to introduce local bindings. It allows
us to introduce more than 1 binding.
• Exceptions allow non-standard control. The key
operations on exceptions are “raise” and “handle”
– Handle is like a “case” in that it can have several clause, separated
by “|”, the first that matches “wins”
7/13/2017
28
Cse321, Programming Languages and Compilers
Introducing new kinds of data
• Objects of an inductive type are allocated in the
heap.
• The abstract interface is to use constructor
(functions) rather than malloc
• This provides some level of type checking, and
abstraction.
• Constructor functions automatically defined. No
need to define like constructors in Java
• Two kinds of constructors. Constants like nil ([]), and
functions like cons (::).
7/13/2017
29
Cse321, Programming Languages and Compilers
Constant Constructors
• Constant constructors are constant
• Can be allocated once at compile-time.
• Like constant pointers that never change.
• The nil constructor [] for lists is an example.
7/13/2017
30
Cse321, Programming Languages and Compilers
Constructor Functions
• Constructor functions allocate in the heap.
• Each constructor may allocate a different amount of
memory
• If we had to do this in C we might write
list cons (void * hd, list tl)
{ list Block = (list) malloc (sizeof (struct listStruct));
Block->Tag = consTag;
Block->Data.consData.hd = hd;
Block->Data.consData.tl = tl;
return (Block);
};
• In ML this is done automatically.
7/13/2017
31
Cse321, Programming Languages and Compilers
Introducing new data and constructors
datatype Tree
Constant constructor,
contains no data
= Tip
| Node of Tree * int * Tree;
Constructor function. Contains 3 fields. The
function Node takes a triple with 3
components. The “of” keyword is used for
constructor functions
val tree1 =
Node(Node(Tip,4,Tip)
,7
,Node(Tip,10,Tip));
7/13/2017
7
4
10
32
Cse321, Programming Languages and Compilers
Pattern Matching functions
fun sum Tip = 0
| sum (Node(x,n,y)) = n + sum x + sum y;
Two constructors, two
clauses
• using binary search tree invariant
fun search n Tip = false
| search n (Node(x,m,y)) =
if n=m
then true
The bar “|”
separates
else if (n < m) then search n x
clauses
else search n y;
7/13/2017
33
Cse321, Programming Languages and Compilers
Searching Trees.
fun search n Tip = false
| search n (Node(x,m,y)) =
if n=m then true
else if (n < m) then search n x else search n y;
•
•
•
•
•
val ex4 = search 3 tree1;
search 3 (Node(Node(Tip,4,Tip),7,Node(Tip,10,Tip)))
search 3 (Node (Tip,4,Tip))
search 3 Tip
false
•
•
•
•
val ex5 = search 10 tree1;
search 10 (Node(Node(Tip,4,Tip),7,Node(Tip,10,Tip)))
search 10 (Node (Tip,10,Tip))
true
7/13/2017
34
Cse321, Programming Languages and Compilers
Expressions
datatype Exp
= Const of int
| Add of Exp * Exp
| Mult of Exp * Exp
| Sub of Exp * Exp;
val exp1 = Add(Const 4,Const 3); (* 4+3 *)
val exp2 = Mult(exp1,exp1); (* (4+3)*(4+3) *)
Mult(Add(Const 4,Const 3)
, Add(Const 4,Const 3));
7/13/2017
35
Cse321, Programming Languages and Compilers
Pattern matching functions
fun ExpValue (Const n) = n
| ExpValue (Add(x,y))
= ExpValue x + ExpValue y
| ExpValue (Mult(x,y))
= ExpValue x * ExpValue y
| ExpValue (Sub(x,y))
= ExpValue x - ExpValue y;
7/13/2017
36
Cse321, Programming Languages and Compilers
More SML
• In SML we use library functions all the time.
– Int.toString
– List.exists
• The list library functions are particularly useful.
–
–
–
–
–
–
–
These library functions often take a function as an argument
List.map : ('a -> 'b) -> 'a list -> 'b list
List.find : ('a -> bool) -> 'a list -> 'a option
List.filter : ('a -> bool) -> 'a list -> 'a list
List.exists : ('a -> bool) -> 'a list -> bool
List.all : ('a -> bool) -> 'a list -> bool
List.foldr : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
• It is worth studying these functions closely
7/13/2017
37
Cse321, Programming Languages and Compilers
List.map captures a pattern
• Add one to every element of a list
– fun addone [] = []
–
| addone (x::xs) = (x + 1) :: addone xs
addone [2,3,4]
val it = [3,4,5] : int list
• Turn a list of ints into a list of strings
– fun stringy [] = []
–
| stringy (x::xs) = (Int.toString x) :: stringy xs
stringy [2,5,9] val it = ["2","5","9"]:string list
• Negate every element of a list
– fun negL [] = []
–
| negL (x::xs) = (not x) :: negL xs
negL [true,3 > 4] val it = [false,true] : bool list
7/13/2017
38
Cse321, Programming Languages and Compilers
Pattern
fun
|
fun
|
fun
|
addone [] = []
addone (x::xs) = (x + 1) :: addone xs
stringy [] = []
stringy (x::xs) = (Int.toString x) :: stringy xs
negL [] = []
negL (x::xs) = (not x) :: negL xs
fun map f [] = []
| map f (x::xs) = (f x) :: (map f xs)
val ex1 = map (fn x => (x+1)) [2,3,4];
val ex1 = [3,4,5] : int list
val ex2 = map Int.toString [2,5,7];
val ex2 = ["2","5","7"] : string list
val ex3 = map not [true, 3 > 4];
val ex3 = [false,true] : bool list
7/13/2017
39
Cse321, Programming Languages and Compilers
Anonymous functions
• Study: (fn x => (x+1))
– It is an anonymous function. A function without a name.
– It has one parameter “x”
– It adds one to its parameter, and returns the result.
(fn x => (x+1)) 4;
val it = 5 : int
• Any non-recursive function can be written anonymously.
– (fn x => x = 5)
» Tests if its parameter is equal to 5
map (fn x => x=5) [1,4,5,3,5];
val it = [false,false,true,false,true] : bool list
– (fn x => fn y => (x,y))
» Has two parameters
» Returns a pair
– (fn (x,y) => (not y, x+3))
» What is the type of this function?
7/13/2017
40
Cse321, Programming Languages and Compilers
List.find
• Used for searching a list.
– List.find : ('a -> bool) -> 'a list -> 'a option
• Uses a function as a parameter to determine if the
search is successful.
• E.g. Is there an even element in a list?
List.find even [1,3,5];
val it = NONE : int option
List.find even [1,3,4];
val it = SOME 4 : int option
7/13/2017
41
Cse321, Programming Languages and Compilers
List.find and anonymous functions
List.find (fn x => x = "Tim")
["Tom", "Jane"];
val it = NONE : string option
List.find (fn x => even x andalso x>10)
[2,4,5,12];
val it = SOME 12 : int option
7/13/2017
42
Cse321, Programming Languages and Compilers
List.filter
Filter keeps some elements, and throws away others.
– List.filter : ('a -> bool) -> 'a list -> 'a list
It uses a function (p) as a parameter to decide which
elements to keep (p x = true), and which to throw
away (p x = false)
val ex6 = List.filter even [1,2,3,4,5,6];
val ex6 = [2,4,6] : int list
7/13/2017
43
Cse321, Programming Languages and Compilers
List.filter and anonymous functions
val people =
[("tim",22),("john",18),("jane",25),("tim",8)];
val ex7 = filter
(fn (nm,age) => nm <> "tim" orelse age>10)
people;
val ex7 =
[("tim",22),("john",18),("jane",25)]
: (string * int) list
7/13/2017
44
Cse321, Programming Languages and Compilers
List.exists
• “exists” is like “find” in that it searches a list
– but rather than the element that completes the search it is only
interested in if such an element exists.
– List.exists : ('a -> bool) -> 'a list -> bool
• Uses a function as a parameter to determine if the
search is successful.
val ex8 = List.exists even [2,3,5];
val ex8 = true : bool
• Note that even if only 1 element in the list causes the
function to be true, exists returns true.
7/13/2017
45
Cse321, Programming Languages and Compilers
List.all
• List.all tests elements in a list for a property. It returns
true only if every element has that property.
– List.all : ('a -> bool) -> 'a list -> bool
• Uses a function as a parameter to perform the test.
val ex9 = List.all even [2,4,5];
val ex9 = false : bool
• List.exists and List.all are related functions.
They are duals.
– not(List.all p xs) = List.exists (fn x => not(p x)) xs
7/13/2017
46
Cse321, Programming Languages and Compilers
List.foldr captures a pattern
• Add up every element in a list.
fun sum [] = 0
| sum (x::xs) = x + (sum xs);
• Compute the maximum element in a list of natural
numbers (Integers >= 0).
fun maximum [] = 0
| maximum (x::xs) = Int.max(x,maximum xs);
• Compute if every element in a list of boolean is true.
fun allTrue [] = true
| allTrue (x::xs) = x andalso (allTrue xs);
7/13/2017
47
Cse321, Programming Languages and Compilers
Pattern
fun sum [] = 0
| sum (x::xs) = x + (sum xs);
fun maximum [] = 0
| maximum (x::xs) = Int.max(x,maximum xs);
fun allTrue [] = true
| allTrue (x::xs) = x andalso (allTrue xs);
fun foldr acc base [ ] = base
| foldr acc base (x::xs)
= acc(x,foldr acc base xs);
7/13/2017
48
Cse321, Programming Languages and Compilers
See the pattern in use.
fun sum [] = 0
| sum (x::xs) = x + (sum xs);
fun sum xs = foldr (op +) 0 xs;
fun maximum [] = 0
| maximum (x::xs) = Int.max(x,maximum xs);
fun maximum xs = foldr Int.max 0 xs;
fun allTrue [] = true
| allTrue (x::xs) = x andalso (allTrue xs);
fun allTrue xs =
foldr (fn (a,b) => a andalso b) true xs;
7/13/2017
49
Cse321, Programming Languages and Compilers
Take another look
What does this function do?
fun ok [] = false
| ok xs = not(exists (fn ys => xs=ys) (!old))
andalso
not(exists (fn ys => xs=ys) (!worklist))
7/13/2017
50
Cse321, Programming Languages and Compilers
The Option Library
- open Option;
opening Option
datatype 'a option = NONE | SOME of 'a
exception Option
val getOpt : 'a option * 'a -> 'a
val isSome : 'a option -> bool
val valOf : 'a option -> 'a
val filter : ('a -> bool) -> 'a -> 'a option
val join : 'a option option -> 'a option
val app : ('a -> unit) -> 'a option -> unit
val map : ('a -> 'b) -> 'a option -> 'b option
val mapPartial : ('a -> 'b option) ->
'a option -> ‘
b option
7/13/2017
51
Cse321, Programming Languages and Compilers
Interesting functions that use Options
• Int.fromString: string -> int option
Int.fromString "234";
val it = SOME 234 : int option
Int.fromString "abc";
val it = NONE : int option
• String.extract: string * int * int option -> string
String.extract("abcde",1,SOME 3);
val it = "bcd" : string
String.extract("abcde",1,NONE);
val it = "bcde" : string
7/13/2017
52
Cse321, Programming Languages and Compilers
More option functions
• List.find: ('a -> bool) -> 'a list -> 'a option
List.find even [1,3,5];
val it = NONE : int option
List.find (fn x => x="tim") ["tom","tim","jane"];
val it = SOME "tim" : string option
• List.getItem: 'a list -> ('a * 'a list) option
– List.getItem [1,2,3,4];
– val it = SOME (1,[2,3,4])
– List.getItem [];
– val it = NONE
7/13/2017
53
Cse321, Programming Languages and Compilers
Using While Loops
fun ident c cs =
let val xs = ref cs
Don’t forget to test
for empty list
val x = ref c
val ans = ref []
in while (not(null(!xs))
andalso
Char.isAlpha (hd (!xs))) do
( ans := !ans @ [!x]
; x := hd(!xs)
; xs := tl(!xs) );
(Id (String.implode (!ans @ [!x])),
!xs)
end
7/13/2017
54
© Copyright 2026 Paperzz