A Third Look At ML

advertisement
Higher-order functions in ML
(Ch. 9)
Functionals
More pattern matching
 Function values and anonymous functions
 Higher-order functions and currying
 Predefined higher-order functions

4/8/2015
IT 327
1
Pattern-Matching in the case expression
fun f 0 = "zero"
| f _ = "non-zero";
match
fun f n =
case n of
0 => "zero" |
_ => "non-zero";
4/8/2015
IT 327
2
Case Expressions
<case-expr> ::= case <expression> of
<match>
<match> ::= <rule>
<match> ::= <rule> | <match>
<rule>
- case
=
3
=
2
=
_
val it
4/8/2015
::= <pattern> => <expression>
1+1 of
=> "three" |
=> "two" |
=> "hmm";
= "two" : string
IT 327
case x of
_::_::c::_
_::b::_
a::_
nil
=>
=>
=>
=>
c |
b |
a |
0
3
Generalizes if
if exp1 then exp2 else exp3
case exp1 of
true => exp2 |
false => exp3
The two expressions above are equivalent
 So if-then-else is really just a special
case of case

4/8/2015
IT 327
4
Behind the Scenes

if := an abbreviation of case

This explains some odd SML/NJ error
messages:
-- if
if 1=1
1=1 then
then 11 else
else 1.0;
1.0;
Error:
branches
not [literal]
agree
Error: types
types of
of if
rules
don't do
agree
[literal]
earlier rule(s): bool -> int
then
int -> real
this branch:
rule: bool
else
branch: real
in rule:
in expression:
false => 1.0
if 1 = 1 then 1 else 1.0
New version of SML shows different message
4/8/2015
IT 327
5
Predefined Functions

Predefined variables bound to functions:
- ord;
val it = fn : char -> int
- ~;
val it = fn : int -> int
- val x = ~;
val x = fn : int -> int
- x 3;
val it = ~3 : int
4/8/2015
IT 327
6
Quick Sort with <
7
5
8
14
6
1
16
2
11 10
9
13
3
15 12
4
7
5
8
4
6
1
3
2
11 10
9
13 16 15 12 14
11 10
9
12 16 15 13 14
<
2
3
1
4
6
8
5
7
<
2
1
3
4
<
1
2
<
6
5
<
3
4
8
7
9
<
5
6
<
<
7
8
10 11 12 14 13 15 16
<
9
<
<
10 11 12 13 14 15 16
< < < < < < < < < < < < < < <
4/8/2015
IT 327
7
Quick Sort with >
7
6
1
We can make a function parameter for
the meaning of ordering
5
8
14
16
2
11 10
9
13 16 15 12 14
11 10
9
13
3
15 12
4
7
5
8
4
6
1
3
2
6
8
5
7
2
3
1
4
3
4
2
3
2
1
>
16 15 13 14 11 10
9
12
>
>
16 15 13 14 11 12 10
>
>
9
8
>
16 15 14 13 12 11 10
>
>
9
7
5
6
>
8
7
>
6
5
>
4
3
> > > > > > > > > > > > > > >
4/8/2015
IT 327
8
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;
fun quicksort nil = nil
|
quicksort [a] = [a]
|
quicksort a =
let
val (x,y) = split a
in
quicksort(x)@quicksort(y)
end;
4/8/2015
IT 327
Quick Sort in ML
This is more
conceptual to the
understanding of the
problem
9
fun split (nil, _) = (nil,nil)
|
split ([a], _) = ([a],nil)
|
split ([a,b], f) =
if f(a,b) then ([a],[b])
else ([b],[a])
|
split (a::b::c, f) =
let
val (x,y) = split (a::c, f)
in
if f(a,b) then (x, b::y)
else (b::x,y)
end;
Quick Sort with
function parameter
fun quicksort (nil,_) = nil
|
quicksort ([a],_) = [a]
|
quicksort (a,f) =
let
val (x,y) = split (a,f)
in
quicksort(x,f)@quicksort(y,f)
end;
4/8/2015
IT 327
10
Anonymous Functions
functions without a name
-calculus
4/8/2015
IT 327
11
Function Values


Functions in ML do not have names but
can be given.
The fun syntax does two separate things:
1.
2.
Creates a new function value
Binds that function value to a name
- fun f x = x + 2;
val f = fn : int -> int
- f 1;
val it = 3 : int
4/8/2015
IT 327
12
Anonymous Functions in ML

Named function:
- fun f x = x + 2;
val f = fn : int -> int
- f 1;
val it = 3 : int

Anonymous function:
A match
- fn x => x + 2;
val it = fn : int -> int
- (fn x => x + 2) 1;
val it = 3 : int
4/8/2015
IT 327
13
The fn Syntax
<fun-expr> ::= fn <match>
We use fn to give an expression whose
value is an (anonymous) function
 The followings are the same effect:

4/8/2015
–
fun f x = x + 2
–
val f = fn x => x + 2
IT 327
14
- fun less (a,b) = a < b;
val intBefore = fn : int * int -> bool
- quicksort ([1,4,3,2,5], less);
val it = [1,2,3,4,5] : int list
Using Anonymous Functions:
- quicksort ([1,4,3,2,5], fn (a,b) => a<b);
val it = [1,2,3,4,5] : int list
- quicksort ([1,4,3,2,5], fn (a,b) => a>b);
val it = [5,4,3,2,1] : int list
Q: Can we do the same in Java or C++?
4/8/2015
IT 327
15
- *;
Error: expression or pattern begins with infix
identifier "*"
The op keyword
Binary operators are special functions
 op gives the underlying function

- op *;
val it = fn : int * int -> int
- op <;
val it = fn : int * int -> bool
- quicksort ([1,4,3,2,5], op <);
val it = [1,2,3,4,5] : int list
4/8/2015
IT 327
16
Higher-order Functions

Every function has an order:
–
–

A function that does not take any functions as
parameters, and does not return a function value, has
order 1
A function that takes a function as a parameter or
returns a function value has order n+1, where n is the
order of its highest-order parameter or returned value
The quicksort we just saw is a second-order
function
A little digression with more precise notions on higher-ordered
Functionals (CiE 2006)
4/8/2015
IT 327
17
Examples:
-> is right-associative
st order
1
int * int -> bool
2nd order
int list * (int * int -> bool) -> int list
int -> int -> int
2nd order
2nd order
(int -> int) * (int -> int) -> (int -> int)
int -> bool -> real -> string
3rd order
nd
('a -> 'b) * ('c -> 'a) -> 'c -> 'b 2 order
int -> int -> int -> int -> int -> int
4/8/2015
IT 327
5th order
18
Haskell B. Curry (1900-1982)
Currying

Curry-Howard logic
a 2-tuple looks like two parameters:
f (2,3);
fun f (a,b) = a + b;

Another way:
fun g a = fn b => a+b;
g 2 3;
(fn b => 2+b) 3

The general name for this is currying
4/8/2015
IT 327
5
19
Curried Addition
- fun f (a,b) = a+b;
val f = fn : int * int -> int
- fun g a = fn b => a+b;
val g = fn : int -> int -> int
- f(2,3);
val it = 5 : int
- g 2 3;
val it = 5 : int
-> is
right-associative
function application is left-associative
 So g 2 3 means ((g 2) 3)

4/8/2015
IT 327
20
Advantages


No tuples: we get to write g 2 3 instead of f(2,3)
The real advantage: we can specialize functions for
particular initial parameters
- fun g a = fn b => a+b;
-val add2 = g 2;
val add2 = fn : int -> int
- add2
val it
- add2
val it
4/8/2015
3;
= 5 : int
10;
= 12 : int
S-m-n Theorem
IT 327
21
Example: 
Let quicksort be written in the Currying
form, in which the comparison function is a
first, curried parameter.
-quicksort (op <) [1,4,3,2,5];
val it = [1,2,3,4,5] : int list
-val sortBackward = quicksort (op >);
val sortBackward = fn : int list -> int list
- sortBackward [1,4,3,2,5];
val it = [5,4,3,2,1] : int list
-val sortForward = quicksort (op <);
val sortForward = fn : int list -> int list
- sortForward [1,4,3,2,5];
val it = [1,2,3,4,5] : int list
4/8/2015
IT 327
22
Multiple Curried Parameters
-fun f (a,b,c) = a+b+c;
val f = fn : int * int * int -> int
- fun g a = fn b => fn c => a+b+c;
val g = fn : int -> int -> int -> int
-f (1,2,3);
val it = 6 : int
- g 1 2 3;
val it = 6 : int
4/8/2015
IT 327
23
Notation For Currying

Explicit intermediate anonymous functions
fun g a = fn b => fn c => a+b+c;

4/8/2015
There is a simpler notation much easier to
read and write
IT 327
24
Easier Notation for Currying
fun f a = fn b => a+b;
same as:
fun f a b = a+b;
fun g a = fn b => fn c => a+b+c;
Same as: fun g a b c = a+b+c;
-fun f a b c d = a+b+c+d;
val f = fn : int -> int -> int -> int -> int
4/8/2015
IT 327
25
Predefined Higher-Order Functions
4/8/2015
– map
(map a function to a list)
– foldr
(fold an operation from the right)
– foldl
(fold an operation from the left)
IT 327
26
The map Function

Apply a function to every element of a list, and
collect a list of results
- map ~ [1,2,3,4];
val it = [~1,~2,~3,~4] : int list
- map (fn x => x+1) [1,2,3,4];
val it = [2,3,4,5] : int list
- map (fn x => x mod 2 = 0) [1,2,3,4];
val it = [false,true,false,true] : bool list
- map (op +) [(1,2),(3,4),(5,6)];
val it = [3,7,11] : int list
4/8/2015
IT 327
27
The map Function Is Curried
- map;
val it = fn : ('a -> 'b) -> 'a list -> 'b list
- map (fn x => x+1) [1,2,3,4];
val it = [2,3,4,5] : int list
-val f = map (op +);
val f = fn : (int * int) list -> int list
- f [(1,2),(3,4)];
val it = [3,7] : int list
4/8/2015
IT 327
28
Define your own map
fun mymap _ nil = nil
| mymap f (a::t) = f a:: mymap f t;
4/8/2015
IT 327
29
The foldr Function
Perform the binary operation on all the elements of a list from the
right (tail)
foldr f c x
where x = [x1, …, xn] and computes:
f x1 , f x2 , f xn 1 , f xn , c
foldr (op +) 0 [1,2,3,4]
evaluates as 1+(2+(3+(4+0)))=10
4/8/2015
IT 327
30
Examples
-foldr (op +) 0 [1,2,3,4];
val it = 10 : int
-foldr (op * ) 1 [1,2,3,4];
val it = 24 : int
-foldr (op ^) "" ["abc","def","ghi"];
val it = "abcdefghi" : string
- foldr (op ::) [5] [1,2,3,4];
val it = [1,2,3,4,5] : int list
4::[5]
4/8/2015
IT 327
31
The foldr Function Is Curried
- foldr;
val it = fn : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
- foldr (op +);
val it = fn : int -> int list -> int
- foldr (op +) 0;
val it = fn : int list -> int
- val sum = foldr (op +) 0;
val sum = fn : int list -> int
- sum [1,2,3,4,5];
val it = 15 : int
4/8/2015
IT 327
32
The foldl Function
Perform the binary operation on all the elements of a list from
the left (head)
foldl f c x where x = [x1, …, xn] and computes:
f xn , f xn1 , f x2 , f x1 , c
So foldl (op +) 0 [1,2,3,4]
 4+(3+(2+(1+0)))=10
foldr (op +) 0 [1,2,3,4]
1+(2+(3+(4+0)))=10
4/8/2015
IT 327
33
Commutative


foldl and foldr are the same if the function is
associative and commutative, like + and *
^ is not commutative
-foldr (op ^) "" ["abc","def","ghi"];
val it = "abcdefghi" : string
-foldl (op ^) "" ["abc","def","ghi"];
val it = "ghidefabc" : string

– is neither associative nor commutative
-foldr (op -) 0 [1,2,3,4];
val it = ~2 : int
- foldl (op -) 0 [1,2,3,4];
val it = 2 : int
4/8/2015
IT 327
34
Homework 6
Chapter 9. Exercises: 3, 6, 10, 26, 27, 28
plus 4 questions to be announced.
4/8/2015
IT 327
35
Download