04/18/23 COSC-3308-01, Lecture 6 1
Programming Language Concepts, COSC-3308-01Lecture 6
Higher-Order Programming and Abstract Data Types
04/18/23 COSC-3308-01, Lecture 6 2
Reminder of the Last Lecture
Last call optimization Recursion versus Iteration Tupled recursion Exceptions Type notation Design methodology
04/18/23 COSC-3308-01, Lecture 6 3
Overview
Higher-order programming Abstract data types October 22, Friday – 9:00am-10:00am
Mid-term exam (20% of the final grade) Lectures 1-5, Tutorials 1-4
04/18/23 COSC-3308-01, Lecture 6 5
Higher-Order Programming
Higher-order programming = the set of programming techniques that are possible with procedure values (lexically-scoped closures).
Higher-order programming is the foundation of secure data abstraction component-based programming and object-oriented programming.
04/18/23 COSC-3308-01, Lecture 6 6
Higher-Order Programming A procedure which has no procedures as
arguments is called first-order. A procedure which has at least one procedure
as argument is called second-order … A procedure is of order n+1 if it has at least
one argument of order n and none of higher order.
Higher-order programming procedures can be of any order.
04/18/23 COSC-3308-01, Lecture 6 7
Remember (I)
Functions are procedures Special syntax, nested syntax, expression syntax They are procedures with one argument as the
result arguments Example:fun {F X} fun {$ Y} X+Y endend
A function that returns a function that is specialized on X
04/18/23 COSC-3308-01, Lecture 6 8
Remember (II)
Successive transformations to procedures1. fun {F X}
fun {$ Y} X+Y endend
2. proc {F X ?R} R = fun {$ Y} X+Y endend
3. proc {F X ?R} R = proc {$ Y ?R1} R1=X+Y endend
04/18/23 COSC-3308-01, Lecture 6 9
Remember (III)3. proc {F X ?R}
R = proc {$ Y ?R1} R1=X+Y endend
F is a procedure value When F is called, its 2nd argument returns a
procedure value ‘?’ is comment indicating output argument
04/18/23 COSC-3308-01, Lecture 6 10
Remember (IV)
declare
fun {F X}
fun {$ Y} X+Y end
end
{Browse F}
G={F 1}
{Browse G}
{Browse {G 2}}
F is a function of one argument, which corresponds to a procedure having two arguments
<P/2 F> G is an unnamed function
<P/2> {G Y} returns 1+Y
3
04/18/23 COSC-3308-01, Lecture 6 11
Remember (V)1. fun {F X}
fun {$ Y} X+Y endend
The type of F fun {F Num}:
fun {$ Num}: Num
04/18/23 COSC-3308-01, Lecture 6 12
Higher-Order Programming
Basic operations: Procedural abstraction: the ability to convert
any statement into a procedure value Genericity: the ability to pass procedure values
as arguments to a procedure call Instantiation: the ability to return procedure
values as results from a procedure call Embedding: the ability to put procedure values
in data structures
04/18/23 COSC-3308-01, Lecture 6 13
Higher-Order Programming
Control abstractions The ability to define control constructs Integer and list loops, accumulator loops,
folding a list (left and right)
04/18/23 COSC-3308-01, Lecture 6 14
Procedural Abstraction
Procedural abstraction is the ability to convert any statement into a procedure value.
Statement
Normal Execution
time
P = proc{$} Statement end
{P}
Delayed Execution
time
04/18/23 COSC-3308-01, Lecture 6 15
Procedural Abstraction A procedure value is usually called a closure,
or more precisely, a lexically-scoped closure A procedure value is a pair: it combines the
procedure code with the contextual environment Basic scheme:
Consider any statement <s> Convert it into a procedure value: P = proc {$} <s> end
Executing {P} has exactly the same effect as executing <s>
04/18/23 COSC-3308-01, Lecture 6 16
The Same Holds for Expressions A procedure value is usually called a closure, or more precisely, a lexically-scoped closure A procedure value is a pair: it combines the
procedure code with the contextual environment Basic scheme:
Consider any expression <E>, embedded in an equality like X = E
Convert it into a function value: F = fun {$} <E> end
Executing X = {F} has exactly the same effect as executing X = E
04/18/23 COSC-3308-01, Lecture 6 17
The Arguments are Evaluateddeclare Z=3fun {F X} {Browse X} 2 endY={F Z}{Browse Y}
X is evaluated as 3
3
2
declare Z=3
fun {F X}
{Browse X}
{Browse {X}} 2
end
Y={F fun {$} Z end}
{Browse Y}
X is evaluated as function value fun {$} Z end
<P/1>
3
2
04/18/23 COSC-3308-01, Lecture 6 18
Example Suppose we want to define the operator andthen (&& in Java) as a function, namely <expression1> andthen <expression2> is false if <expression1> is false, avoiding the evaluation of <expression2> (Exercise 2.8.6, page 109).
Attempt:fun {AndThen B1 B2}
if B1 then B2 else false end
end
if {AndThen X>0 Y>0} then … else …
04/18/23 COSC-3308-01, Lecture 6 19
Example
Does not work as wished because both X>0 and Y>0 are evaluated.
So, even if X>0 is false, Y should be bound in order to evaluate the expression Y>0!
fun {AndThen B1 B2}
if B1 then B2 else false end
end
if {AndThen X>0 Y>0} then … else …
04/18/23 COSC-3308-01, Lecture 6 20
Exampledeclarefun {AndThen B1 B2} if B1 then B2 else false endendX=~3Yif {AndThen X>0 Y>0} then {Browse 1}else {Browse 2}end Display nothing since Y is unbound! When called, all function’s arguments are evaluated.
04/18/23 COSC-3308-01, Lecture 6 21
Solution: Use Procedural Abstractions
fun {AndThen B1 B2}
if {B1} then {B2} else false end
end
if {AndThen fun{$} X>0 end fun{$} Y>0 end}
then … else … end
04/18/23 COSC-3308-01, Lecture 6 22
Example. Solutiondeclare
fun {AndThen BP1 BP2}
if {BP1} then {BP2} else false end
end
X=~3
Y
if {AndThen
fun{$} X>0 end
fun{$} Y>0 end}
then {Browse 1} else {Browse 2} end Display 2 (even if Y is unbound)
04/18/23 COSC-3308-01, Lecture 6 23
Genericity
To make a function generic is to let any specific entity (i.e., any operation or value) in the function body become an argument of the function.
The entity is abstracted out of the function body.
04/18/23 COSC-3308-01, Lecture 6 24
Genericity
Replace specific entities (zero 0 and addition +) by function arguments.
fun {SumList Ls}case Ls of nil then 0[] X|Lr then X+{SumList Lr}end
end
04/18/23 COSC-3308-01, Lecture 6 25
Genericityfun {SumList L}
case L of nil then 0[] X|L2 then X+{SumList L2}end
end
fun {FoldR L F U}case L of nil then U[] X|L2 then {F X {FoldR L2 F U}}end
end
04/18/23 COSC-3308-01, Lecture 6 26
Genericity SumList
fun {SumList Ls} {FoldR Ls fun {$ X Y} X+Y end 0 }end{Browse {SumList [1 2 3 4]}}
04/18/23 COSC-3308-01, Lecture 6 27
Genericity ProductList
fun {ProductList Ls} {FoldR Ls fun {$ X Y} X*Y end 1 }end{Browse {ProductList [1 2 3 4]}}
04/18/23 COSC-3308-01, Lecture 6 28
Genericity Some
fun {Some Ls} {FoldR Ls fun {$ X Y} X orelse Y end false } end{Browse {Some [false true false]}}
04/18/23 COSC-3308-01, Lecture 6 29
List Mapping
Mapping each element recursively calling function for each element Snoctruct list that takes output
Separate function calling by passing function as argument.
04/18/23 COSC-3308-01, Lecture 6 30
Other Generic Functions: Map
fun {Map Xs F} case Xs of nil then nil [] X|Xr then {F X}|{Map Xr F} endend{Browse {Map [1 2 3]
fun {$ X} X*X end}}
04/18/23 COSC-3308-01, Lecture 6 31
Other Generic Functions: Filterfun {Filter Xs P} case Xs of nil then nil [] X|Xr andthen {P X} then X|{Filter Xr P} [] X|Xr then {Filter Xr P} endend
{Browse {Filter [1 2 3] IsOdd}}
04/18/23 COSC-3308-01, Lecture 6 32
Instantiation Instantiation: the ability to return procedure
values as results from a procedure call. A factory of specialized functions.
declarefun {Add X}
fun {$ Y} X+Y endend
Inc = {Add 1}{Browse {Inc 5}} % shows 6
04/18/23 COSC-3308-01, Lecture 6 33
Explanations for Nesting Operator $ The previous Oz code can be rewritten as:
declare
fun {Add X}
Z = fun {$ Y} X+Y end
Z
end
Inc = {Add 1} % Inc is bound to value of Z
{Browse {Inc 5}} % shows 6
04/18/23 COSC-3308-01, Lecture 6 34
Embedding Embedding is when procedure values are put
in data structures. Embedding has many uses:
Modules: a module is a record that groups together a set of related operations (procedures).
Software components: a software component is a generic function that takes a set of modules as its arguments and returns a new module. It can be seen as specifying a module in terms of the modules it needs.
04/18/23 COSC-3308-01, Lecture 6 35
Embedding. Exampledeclare Algebralocal proc {Add X Y ?Z} Z=X+Y end proc {Mul X Y ?Z} Z=X*Y endin Algebra=op(add:Add mul:Mul) endA=2B=3{Browse {Algebra.add A B}}{Browse {Algebra.mul A B}}
Add and Mul are procedures embedded in a data structure.
04/18/23 COSC-3308-01, Lecture 6 36
Integer Loop Abstractions Integer loop: repeats an operation with a sequence
of integers:
proc {For I J P} if I > J then skip else {P I} {For I+1 J P} endend{For 1 10 Browse}
Linguistic abstraction for integer loops:for I in 1..10 do {Browse I} end
04/18/23 COSC-3308-01, Lecture 6 37
List Loop Abstractions List loop: repeats an operation for all elements of a list:
proc {ForAll Xs P} case Xs of nil then skip [] X|Xr then {P X} {ForAll Xr P} endend
{ForAll [a b c d] proc{$ I} {Browse I} end}
04/18/23 COSC-3308-01, Lecture 6 38
List Loop Abstractions
proc {ForAll Xs P} case Xs of nil then skip [] X|Xr then {P X} {ForAll Xr P} endend
Linguistic abstraction for list loops:
for I in [a b c d] do {Browse I}end
04/18/23 COSC-3308-01, Lecture 6 39
Other Examples
{Filter Xs F}returns all elements of Xs for which F returns true
{Some Xs F}tests whether Xs has an element for which F returns true
{All Xs F}tests whether F returns true for all elements of Xs
04/18/23 COSC-3308-01, Lecture 6 40
Folding Lists
Consider computing the sum of list elements …or the product …or all elements appended to a list …or the maximum …
What do they have in common?
Example: SumList
04/18/23 COSC-3308-01, Lecture 6 41
SumList: Naive
fun {SumList Xs}
case Xs
of nil then 0
[] X|Xr then {SumList Xr}+X
end
end
First step: make tail-recursive with accumulator.
04/18/23 COSC-3308-01, Lecture 6 42
SumList: Tail-Recursive
fun {SumList Xs N} case Xs of nil then N [] X|Xr then {SumList Xr N+X} endend{SumList Xs 0}
Question: what is about computing the sum? what is generic?
04/18/23 COSC-3308-01, Lecture 6 43
SumList: Tail-Recursive
fun {SumList Xs N} case Xs of nil then N [] X|Xr then {SumList Xr N+X} endend{SumList Xs 0}
Question: what is about computing the sum? what is generic?
04/18/23 COSC-3308-01, Lecture 6 44
How Does SumList Compute?
{SumList [2 5 7] 0} =
{SumList [5 7] 0+2} =
{SumList [7] (0+2)+5} =
{SumList nil ((0+2)+5)+7} = …
04/18/23 COSC-3308-01, Lecture 6 45
SumList Slightly Rewritten…
{SumList [2 5 7] 0} =
{SumList [5 7] {F 0 2}} =
{SumList [7] {F {F 0 2} 5}} =
{SumList nil {F {F {F 0 2} 5} 7} =
…
where F is
fun {F X Y} X+Y end
04/18/23 COSC-3308-01, Lecture 6 46
Left-Folding
Two values define “folding” initial value 0 for SumList binary function + for SumList
Left-folding {FoldL [x1 … xn] F S}
{F … {F {F S x1} x2} … xn}
or
(…((S F x1) F x2) … F xn)
04/18/23 COSC-3308-01, Lecture 6 47
Left-Folding
Two values define “folding” initial value 0 for SumList binary function + for SumList
Left-folding {FoldL [x1 … xn] F S}
{F … {F {F S x1} x2} … xn}
or
(…((S F x1) F x2) … F xn)
left is here!
04/18/23 COSC-3308-01, Lecture 6 48
FoldL
fun {FoldL Xs F S}
case Xs
of nil then S
[] X|Xr then {FoldL Xr F {F S X}}
end
end
04/18/23 COSC-3308-01, Lecture 6 49
SumList with FoldL
local
fun {Plus X Y} X+Y end
in
fun {SumList Xs}
{FoldL Xs Plus 0}
end
end
04/18/23 COSC-3308-01, Lecture 6 50
Properties of FoldL
Tail recursive First element of list is folded first…
what does that mean?
04/18/23 COSC-3308-01, Lecture 6 51
What Does This Do?
local
fun {Snoc Xr X}
X|Xr
end
in
fun {Foo Xs}
{FoldL Xs Snoc nil}
end
end
04/18/23 COSC-3308-01, Lecture 6 52
How Does Foo Compute?
{Foo [a b c]} =
{FoldL [a b c] Snoc nil} =
{FoldL [b c] Snoc {Snoc nil a}} =
{FoldL [b c] Snoc [a]} =
{FoldL [c] Snoc {Snoc [a] b}} =
{FoldL [c] Snoc [b a]} =
{FoldL nil Snoc {Snoc [b a] c}} =
{FoldL nil Snoc [c b a]} = [c b a]
04/18/23 COSC-3308-01, Lecture 6 53
Right-Folding
Two values define “folding” initial value binary function
Right-folding {FoldR [x1 … xn] F S}
{F x1 {F x2 … {F xn S} …}}
or
x1F(x2 F( … (xn F S) … ))
04/18/23 COSC-3308-01, Lecture 6 54
Right-Folding
Two values define “folding” initial value binary function
Right-folding {FoldR [x1 … xn] F S}
{F x1 {F x2 … {F xn S} …}}
or
x1F(x2 F( … (xn F S) … ))
right is here!
04/18/23 COSC-3308-01, Lecture 6 55
FoldR
fun {FoldR Xs F S}
case Xs
of nil then S
[] X|Xr then {F X {FoldR Xr F S}}
end
end
04/18/23 COSC-3308-01, Lecture 6 57
FoldL or FoldR?
FoldL and FoldR compute the same value, if function F commutes:
{F X Y}=={F Y X}
If function commutes:FoldL FoldL tail-recursive
Otherwise: FoldL or FoldR depending on required order of result
04/18/23 COSC-3308-01, Lecture 6 58
Example: Appending Lists
Given: list of lists[[a b] [1 2] [e] [g]]
Task: compute all elements in one list in order
Solution:
fun {AppAll Xs}
{FoldR Xs Append nil}
end Question: What would happen with FoldL?
04/18/23 COSC-3308-01, Lecture 6 59
What would happen with FoldL?
fun {AppAllLeft Xs}
{FoldL Xs Append nil}
end
{AppAllLeft [[a b] [1 2] [e] [g]]} =
{FoldL [[a b] [1 2] [e] [g]] Append nil} =
{FoldL [[1 2] [e] [g]] Append {Append nil [a b]}}= ...
04/18/23 COSC-3308-01, Lecture 6 60
How Does AppAllLeft Compute?{FoldL [[1 2] [e] [g]] Append [a b]} =
{FoldL [[e] [g]] Append {Append [a b] [1 2]}} =
{FoldL [[e] [g]] Append [a b 1 2]} =
{FoldL [[g]] Append {Append [a b 1 2] [e]}} =
{FoldL [[g]] Append [a b 1 2 e]} =
{FoldL nil Append {Append [a b 1 2 e] [g]}} =
{FoldL nil Append [a b 1 2 e g]} =
= [a b 1 2 e g]
04/18/23 COSC-3308-01, Lecture 6 61
Summary so far Many operations can be partitioned into
pattern implementing recursion application of operations
operations to be applied
Typical patterns Map mapping elements FoldL/FoldR folding elements Filter filtering elements Sort sorting elements …
04/18/23 COSC-3308-01, Lecture 6 63
Data Types
Data type set of values operations on these values
Primitive data types records numbers …
Abstract data types completely defined by its operations (interface) implementation can be changed without changing use
04/18/23 COSC-3308-01, Lecture 6 64
Motivation
Sufficient to understand interface only.
Software components can be developed independently, as long as only the interface is used.
Developers need not to know implementation details.
04/18/23 COSC-3308-01, Lecture 6 65
Outlook
How to define abstract data types
How to organize abstract data types
How to use abstract data types
04/18/23 COSC-3308-01, Lecture 6 66
Abstract data types (ADTs) A type is abstract if it is completely defined by
its set of operations, regardless of the implementation.
ADTs: it is possible to change the implementation of an ADT without changing its use.
The ADT is described by a set of procedures Including how to create a value of the ADT.
These operations are the only thing that a user of the abstraction can assume.
04/18/23 COSC-3308-01, Lecture 6 67
Example: stack
Assume we want to define a new data type stack T whose elements are of any type T.
We define the following operations (with type definitions):
fun {NewStack}: stack Tfun {Push stack T T }: stack Tproc {Pop stack T ?T ?stack T}fun {IsEmpty stack T}: Bool
04/18/23 COSC-3308-01, Lecture 6 68
Example: stack (algebraic properties)
Algebraic properties are logical relations between ADT’s operations.
These operations normally satisfy certain laws (properties):
{IsEmpty {NewStack}} = true For any stack S, {IsEmpty {Push S}} = false For any E and S, {Pop {Push S E} E S} holds. For any stack S, {Pop {NewStack} S} raises error.
04/18/23 COSC-3308-01, Lecture 6 69
stack (implementation I) using listsfun {NewStack} nil end
fun {Push S E} E|S end
proc {Pop E|S ?E1 ?S1}
E1 = E
S1 = S
end
fun {IsEmpty S} S==nil end
04/18/23 COSC-3308-01, Lecture 6 70
stack (implementation II) using tuplesfun {NewStack} emptyStack end
fun {Push S E} stack(E S) end
proc {Pop stack(E S) E1 S1} E1 = E
S1 = S
end
fun {IsEmpty S} S==emptyStack end
04/18/23 COSC-3308-01, Lecture 6 71
Why the Stack is Abstract?
A program that uses the stack will work with either implementation (gives the same result).
declare Top S4
% ... either implementation
S1={NewStack}
S2={Push S1 2}
S3={Push S2 5}
{Pop S3 Top S4}
{Browse Top} 5
04/18/23 COSC-3308-01, Lecture 6 72
What is a Dictionary?
A dictionary is a finite mapping from a set of simple constants to a set of language entities.
Each constant maps to one language entity. The constants are called keys because they
unlock the path to the entity, in some intuitive sense.
We will use atoms or integers as constants. Goal: create the mapping dynamically, i.e.,
by adding new keys during the execution.
04/18/23 COSC-3308-01, Lecture 6 73
Example: Dictionaries Designing the interface{MakeDict}
returns new dictionary{DictMember D F}
tests whether feature F is member of dictionary D{DictAccess D F}
returns the value of feature F in D{DictAdjoin D F X}
returns the dictionary with value X at feature F adjoined
Interface depends on purpose, could be richer.
04/18/23 COSC-3308-01, Lecture 6 74
Using the Dict ADT
Now we can write programs using the ADT without even having an implementation for it.
Implementation can be provided later. Eases software development in large teams.
04/18/23 COSC-3308-01, Lecture 6 75
Implementing the Dict ADT
Now we can decide on a possible implementation for the Dict ADT: based on pairlists, based on records.
Regardless on what we decide, programs using the ADT will work! the interface is a contract between use and
implementation.
04/18/23 COSC-3308-01, Lecture 6 76
Dict: Pairlistsfun {MakeDict} nilendfun {DictMember D F} case D of nil then false [] G#X|Dr then if G==F then true else {DictMember Dr F} end endend Example: telephone book[name1#62565243 name2#67893421 taxi1#65221111...]
04/18/23 COSC-3308-01, Lecture 6 77
Dict: Recordsfun {MakeDict} mr %start making the recordendfun {DictMember D F} {HasFeature D F}endfun {DictAccess D F} D.Fendfun {DictAdjoin D F X} {AdjoinAt D F X}end Example: telephone bookd(name1:62565243 name2:67893421 taxi1:65521111...)
04/18/23 COSC-3308-01, Lecture 6 78
HasFeature and AdjoinAtdeclareX=p(n:'Joe' age:26)Y={Value.'.' X n}{Browse Y} Z={Value.hasFeature X age}{Browse Z} U={HasFeature X age}{Browse U} V={AdjoinAt X s 'm'}{Browse V} T={AdjoinAt V age 27}{Browse T}
'Joe'
true
true
p(age:26 n:'Joe' s:'m')
p(age:27 n:'Joe' s:'m')
04/18/23 COSC-3308-01, Lecture 6 79
Evolution of ADTs Important aspect of developing ADTs
start with simple (possibly inefficient) implementation;
refine to better (more efficient) implementation; refine to carefully chosen implementation:
hash table search tree
All of evolution is local to ADT: no change of programs using ADT is needed!
04/18/23 COSC-3308-01, Lecture 6 81
Reading suggestions
From [van Roy,Haridi; 2004] Chapter 3, Sections 3.2-3.9 Exercises 2.9.8, 3.10.6-3.10.17
04/18/23 COSC-3308-01, Lecture 6 82
Coming up next
Declarative concurrency, and Demand-driven execution Chapter 3, Sections 3.4-3.8 Chapter 4, Sections 4.1-4.5