A Second Look At ML

Download Report

Transcript A Second Look At ML

ML Again ( Chapter 7)
Patterns
 Local variable definitions
 Two sorting examples

The implementation using functional languages is
closer to the concepts of the solutions.
4/13/2015
IT 327
1

fun f n = n*n;

fun g (a,b) = a*b;
Both n and (a,b) are
patterns.
n is a pattern of integers;
(a, b) is a pattern of 2-tuple of integers.
For match and bind (most of the time)
f
f
g
g
2; (matched)
(2,3); (not matched)
2; (not matched)
(2,3); (matched)
4/13/2015
IT 327
2
Underscore is a Pattern
- fun f _ = "yes";
val f = fn : 'a -> string
- f 34.5;
val it = "yes" : string
- f [];
val it = "yes" : string

The underscore matches anything,
but does not bind it to a variable
fun f x = "yes";
4/13/2015
IT 327
3
Constants are Patterns
- fun f 0 = "yes";
Warning: match nonexhaustive
0 => ...
val f = fn : int -> string
- f 0;
val it = "yes" : string
Any constant of an equality type can be
used as a pattern
 But not:
fun f 0.0 = "yes";

4/13/2015
IT 327
4
Non-Exhaustive Match
“match non-exhaustive” warning
 Meaning: f was defined using a pattern that
didn’t cover all the domain type (int)


So you may get runtime errors like this:
- f 0;
val it = "yes" : string
- f 1;
uncaught exception nonexhaustive match failure
4/13/2015
IT 327
5
Lists Of Patterns As Patterns
- fun f [a,_] = a;
Warning: match nonexhaustive
a :: _ :: nil => ...
val f = fn : 'a list -> 'a
- f [#"f",#"g"];
val it = #"f" : char



4/13/2015
You can use a list of patterns as a pattern Why not 1?
This example matches any list of length 2
It treats a and _ as sub-patterns, binding a
to the first list element
IT 327
6
Cons Of Patterns As A Pattern
- fun f (x::xs) = x;
Warning: match nonexhaustive
x :: xs => ...
val f = fn : 'a list -> 'a
- f [1,2,3];
val it = 1 : int



4/13/2015
You can use a cons of patterns as a pattern
x::xs matches any non-empty list, and binds x
to the head and xs to the tail
Parentheses around x::xs are for precedence
IT 327
7
Little Summary






4/13/2015
A variable is a pattern that matches anything, and binds to it
A _ is a pattern that matches anything
A constant (of an equality type) is a pattern that matches
only that constant
A tuple of patterns is a pattern that matches any tuple of the
right size, whose contents match the sub-patterns
A list of patterns is a pattern that matches any list of the
right size, whose contents match the sub-patterns
A cons (::) of patterns is a pattern that matches any nonempty list whose head and tail match the sub-patterns
IT 327
8
Multiple Patterns for Functions
- fun f 0 = "zero"
= |
f 1 = "one";
Warning: match nonexhaustive
0 => ...
1 => ...
val f = fn : int -> string;
- f 1;
val it = "one" : string

You can define a function by listing
alternate patterns
4/13/2015
IT 327
9
Syntax
<fun-def> ::= fun <fun-bodies> ;
<fun-bodies> ::= <fun-body>
<fun-bodies> ::= <fun-body> | <fun-bodies>
<fun-body> ::= <fun-name> <pattern> = <expression>
To list alternate patterns for a function
 You must repeat the same function name in
each alternative

We just hit the limitation of CFG
4/13/2015
IT 327
10
Overlapping Patterns
- fun f 0 = "zero"
= |
f _ = "non-zero";
val f = fn : int -> string;
- f 0;
val it = "zero" : string
- f 34;
val it = "non-zero" : string
Patterns may overlap
 ML uses the first match for a given
argument

4/13/2015
IT 327
11
Pattern-Matching Style

Two alternatives:
fun f 0 = "zero"
|
f _ = "non-zero";
fun f n =
if n = 0
then "zero"
else "non-zero";


4/13/2015
Pattern-matching style is preferred in ML
shorter and more legible
IT 327
12
Pattern-Matching Examples
fun fact n =
if n = 0 then 1 else n * fact(n-1);
fun fact 0 = 1
|
fact n = n * fact(n-1);
fun reverse L =
if null L then nil
else reverse(tl L) @ [hd L];
fun reverse nil = nil
|
reverse (first::rest) = reverse rest@[first];
4/13/2015
IT 327
13
A Restriction
How to explain this?
fun f (a,a) = …
|
f (a,b) = …
This is not legal,
but why?
fun f (a,b) =
if (a=b) then …
else …
4/13/2015
IT 327
14
Patterns in val
- val (a,b) = (1,2.3);
val a = 1 : int
val b = 2.3 : real
- val a::b = [1,2,3,4,5];
Warning: binding not exhaustive
a :: b = ...
val a = 1 : int
val b = [2,3,4,5] : int list
4/13/2015
IT 327
15
Local Variable Definitions
<let-exp> ::= let <definitions> in <expression> end
- let val x = 1 val y = 2 in x+y end;
val it = 3 : int;
- x;
Error: unbound variable or constructor: x
let
val x = 1
val y = 2
in
x+y
End;
4/13/2015
This alone is not very useful!
We can put it into a function definition
IT 327
16
Long Expressions with let
fun days2ms days =
days*24.0*60.0*60.0*1000.0;
fun days2ms days =
let
val hours = days * 24.0
val minutes = hours * 60.0
val seconds = minutes * 60.0
in
seconds * 1000.0
end;
4/13/2015
IT 327
17
You should have known this well.
Merge Sort
(if you have taken 279)
Merge two sorted lists
3
4/13/2015
5
7
8
1
IT 327
2
6
18
Merge
Sort
4/13/2015
7
5
3
8
2
1
6
7
5
3
8
2
1
6
7
5
3
8
2
1
6
7
5
3
8
2
1
5
7
3
8
1
2
3
5
7
8
1
2
1
2
3
IT 327
5
6
7
6
8
19
How to
split
7
5
3
8
2
1
6
7
5
3
8
2
1
6
In ML, it’s a bit difficult to do this
We have hd, tl and ::
7
5
3
8
2
1
6
7
3,8,2,1,6
5
4/13/2015
Recursively
IT 327
20
halve
fun halve nil = (nil, nil)
|
halve [a] = ([a], nil)
|
halve (a::b::cs) =
let
val (x, y) = halve cs
in
(a::x, b::y)
end;
-halve [1];
-val it = ([1],[]) : int list * int list
-halve [1,2];
val it = ([1],[2]) : int list * int list
- halve [1,2,3,4,5,6];
val it = ([1,3,5],[2,4,6]) : int list * int list
4/13/2015
IT 327
21
merge
Recursively
7
xs
5
ys
5
fun merge (nil, ys) = ys
|
merge (xs, nil) = xs
|
merge (x::xs, y::ys) =
if (x < y)
then x :: merge(xs, y::ys)
else y :: merge(x::xs, ys);
4/13/2015
IT 327
22
Merge Sort
fun mergeSort nil = nil
|
mergeSort [a] = [a]
|
mergeSort theList =
let
val (x, y) = halve theList
in
merge(mergeSort x, mergeSort y)
end;

4/13/2015
int list -> int list,
IT 327
23
Merge Sort At Work
These two functions
can be defined locally.
- fun mergeSort nil = nil
= |
mergeSort [a] = [a]
= |
mergeSort theList =
here
=
let
=
val (x, y) = halve theList
=
in
=
merge(mergeSort x, mergeSort y)
=
end;
val mergeSort = fn : int list -> int list
- mergeSort [4,3,2,1];
val it = [1,2,3,4] : int list
- mergeSort [4,2,3,1,5,3,6];
val it = [1,2,3,3,4,5,6] : int list
4/13/2015
IT 327
24
fun mergeSort nil = nil
|
mergeSort [e] = [e]
|
mergeSort theList =
let (* fun and var defined locally *)
fun halve nil = (nil, nil)
|
halve [a] = ([a], nil)
|
halve (a::b::cs) =
let val (x, y) = halve cs
in (a::x, b::y)
end;
fun merge (nil, ys) = ys
|
merge (xs, nil) = xs
|
merge (x::xs, y::ys) =
if (x < y) then x :: merge(xs, y::ys)
else y :: merge(x::xs, ys);
val (x, y) = halve theList
in
merge(mergeSort x, mergeSort y)
end;
4/13/2015
IT 327
25
Quick Sort
7
5
7
8
5
14
8
4
6
1
6
1
16
2
11 10
9
13
3
<
2 < 11 10
9
13 16 15 12 14
<
2
3
8
<
2
<
1
4/13/2015
3
<
4
5
7 <9
<
6
9
4
12 < 16 15 13 14
<
5 <8
4< 6
<
2
7 < 11 10
5
<
1< 3
15 12
<
4< 6
1
3
7
10 <11 12 < 14 13 < 15 16
<
8
9
IT 327
<
<
<
<
10 11 12 13 14 15 16
26
pivot
Quick Sort
7
5
84
3
14
6
1
2 16
16
2
11 10
9
13 14
3
15 12
8
4
2
5
4
3
6
1
7
16 11 10
9
13 14 15 12
8
1
2
4
3
6
5
7
8
11 10
9
13 14 15 12 16
1
2
3
4
6
5
7
8
11 10
9
13 14 15 12 16
1
2
3
4
5
6
7
8
9
10 11 13 14 15 12 16
1
2
3
4
5
6
7
8
9
10 11 12 13 15 14 16
1
2
3
4
5
6
7
8
9
10 11 12 13 14 15 16
1
2
3
4
5
6
7
8
9
10 11 12 13 14 15 16
Using imperative PL’s, we have to explicitly implement these iterations.
4/13/2015
IT 327
27
Quick Sort
in Java
private void SwapTwo(int A[], int i, int j){
int temp = A[i];
A[i]=A[j];
A[j]=temp;
}
public void QuickSort(int A[], int h, int t){
if (h == t) return;
int i=h+1, j=t;
We have to explicitly
if (i==j) {
implement these
if (A[h] > A[i]) SwapTwo(A,h,i);
return;
iterations.
}
while (i < j) {
while (A[h] >= A[i] && i < t) i++;
while (A[h] <= A[j] && j > h) j--;
if (i < j) SwapTwo(A,i++,j--);
if (i==j && A[h]>A[i]) SwapTwo(A,h,i);
}
QuickSort(A,h,i-1);
QuickSort(A,i,t);
}
4/13/2015
IT 327
28
Quick Sort in ML
fun split nil = (nil,nil)
|
split [a] = ([a],nil)
|
split (a::b::tail) =
let
val (x,y) = split (a::tail)
in
if (a < b) then (x, b::y)
else (b::x, y)
end;
fun quicksort nil = nil
|
quicksort [a] = [a]
|
quicksort a =
let
val (x,y) = split a
in
quicksort(x)@quicksort(y)
end;
Anything wrong?
4/13/2015
pivot
This is more
conceptual to the
understanding of the
problem
How about split [2,2] ?
IT 327
29
fun split nil = (nil,nil)
|
split [a] = ([a],nil)
|
split [a,b] =
if (a <= b) then ([a],[b])
else ([b],[a])
|
split (a::b::c) =
let
val (x,y) = split (a::c)
in
if (a < b) then (x, b::y)
else (b::x, y)
end;
Quick Sort in ML
Force to split when there
are two elements.
fun quicksort nil = nil
|
quicksort [a] = [a]
|
quicksort a =
let
val (x,y) = split a
in
quicksort(x)@quicksort(y)
end;
4/13/2015
IT 327
30
Homework 4
Chapter 7. Exercise: 2, 3, 5, 7, 8, 9, 10
Due Oct. 20
4/13/2015
IT 327
31