ProgrammingLanguages
andTechniques
(CIS120)
Lecture10
September23,2016
The‘fold’designpattern
Abstracttypes
Sets
Announcements
• Homework3
– dueTuesdayat11:59:59pm
– nextHWavailableafterthemidterm
• Midterm1
– Friday,February10, inclass
– CoversmaterialthroughChapter10
– Reviewmaterials(oldexams)oncoursewebsite
– Reviewsession:Wednesday,6-8pminWu&Chen
The‘fold’designpattern
Refactoringcode,again
• Isthereapatterninthedefinitionofthesetwofunctions?
let rec exists (l : bool list) : bool =
begin match l with
| [] -> false
| h :: t -> h || exists t
end
let rec acid_length (l : acid list) : int =
begin match l with
| [] -> 0
| h :: t -> 1 + acid_length t
end
basecase:
Simpleanswerwhen
thelistisempty
combinestep:
Dosomethingwith
theheadofthelist
andtheresultofthe
recursivecall
• Canwefactoroutthispatternusingfirst-classfunctions?
CIS120
Preparation
let rec exists (l : bool list) : bool =
begin match l with
| [] -> false
| h :: t -> h || exists t
end
let rec acid_length (l : acid list) : int =
begin match l with
| [] -> 0
| h :: t -> 1 + acid_length t
end
CIS120
Preparation
let rec helper (l : bool list) : bool =
begin match l with
| [] -> false
| h :: t -> h || helper t
end
let exists (l : bool list) = helper l
let rec helper (l : acid list) : int =
begin match l with
| [] -> 0
| h :: t -> 1 + helper t
end
let acid_length (l : acid list) = helper l
CIS120
AbstractingwithrespecttoBase
let rec helper (l : bool list) : bool =
begin match l with
| [] -> false
| h :: t -> h || helper t
end
let exists (l : bool list) = helper l
let rec helper (l : acid list) : int =
begin match l with
| [] -> 0
| h :: t -> 1 + helper t
end
let acid_length (l : acid list) = helper l
CIS120
AbstractingwithrespecttoBase
let rec helper (base : bool) (l : bool list) : bool =
begin match l with
| [] -> base
| h :: t -> h || helper base t
end
let exists (l : bool list) = helper false l
let rec helper (base : int) (l : acid list) : int =
begin match l with
| [] -> base
| h :: t -> 1 + helper base t
end
let acid_length (l : acid list) = helper 0 l
CIS120
AbstractingwithrespecttoCombine
let rec helper (base : bool) (l : bool list) : bool =
begin match l with
| [] -> base
| h :: t -> h || helper base t
end
let exists (l : bool list) = helper false l
let rec helper (base : int) (l : acid list) : int =
begin match l with
| [] -> base
| h :: t -> 1 + helper base t
end
let acid_length (l : acid list) = helper 0 l
CIS120
AbstractingwithrespecttoCombine
let rec helper (base : bool) (l : bool list) : bool =
begin match l with
| [] -> base
| h :: t -> h || helper base t
end
let exists (l : bool list) = helper false l
let rec helper (base : int) (l : acid list) : int =
begin match l with
| [] -> base
| h :: t -> 1 + helper base t
end
let acid_length (l : acid list) = helper 0 l
CIS120
AbstractingwithrespecttoCombine
let rec helper (combine : bool -> bool -> bool)
(base : bool) (l : bool list) : bool =
begin match l with
| [] -> base
| h :: t -> combine h (helper combine base t)
end
let exists (l : bool list) =
helper (fun (h:bool) (acc:bool) -> h || acc) false l
let rec helper (combine : acid -> int -> int)
(base : int) (l : acid list) : int =
begin match l with
| [] -> base
| h :: t -> combine h (helper combine base t)
end
let acid_length (l : acid list) =
helper (fun (h:acid) (acc:int) -> 1 + acc) 0 l
CIS120
MakingtheHelperGeneric
let rec helper (combine : ‘a -> ‘b -> ‘b)
(base : ‘b) (l : ‘a list) : ‘b =
begin match l with
| [] -> base
| h :: t -> combine h (helper combine base t)
end
let exists (l : bool list) =
helper (fun (h:bool) (acc:bool) -> h || acc) false l
let rec helper (combine : ‘a -> ‘b -> ‘b)
(base : ‘b) (l : ‘a list) : ‘b =
begin match l with
| [] -> base
| h :: t -> combine h (helper combine base t)
end
let acid_length (l : acid list) =
helper (fun (h:acid) (acc:int) -> 1 + acc) 0 l
CIS120
ListFold
let rec fold (combine: 'a -> 'b -> 'b)
(base:'b) (l : 'a list) : 'b =
begin match l with
| [] -> base
| x :: t -> combine x (fold combine base t)
end
let exists (l : bool list) : bool =
fold (fun (h:bool) (acc:bool) -> h || acc) false l
let acid_length (l : acid list) : int =
fold (fun (h:acid) (acc:int) -> 1 + acc) 0 l
•
fold (a.k.a.Reduce)
– Liketransform,foundationalfunctionforprogrammingwithlists
– Capturesthepatternofrecursionoverlists
– AlsopartofOCamlstandardlibrary(List.fold_right)
– Similaroperationsforotherrecursivedatatypes (fold_tree)
CIS120
Howwouldyourewritethisfunction
let rec sum (l : int list) : int =
begin match l with
| [] -> 0
| h :: t -> h + sum t
end
usingfold?Whatshouldbetheargumentsforbaseand
combine?
1. combineis:
baseis:
(fun (h:int) (acc:int) -> acc + 1)
0
2. combineis:
baseis:
(fun (h:int) (acc:int) -> h + acc)
0
3. combineis:
baseis:
(fun (h:int) (acc:int) -> h + acc)
1
4. sumcan’tbewrittenwithfold.
CIS120
Answer:2
Howwouldyourewritethisfunction
let rec reverse (l : int list) : int list =
begin match l with
| [] -> []
| h :: t -> reverse t @ [h]
end
usingfold?Whatshouldbetheargumentsforbaseandcombine?
1. combineis:
baseis:
(fun (h:int) (acc:int list) -> h :: acc)
0
2. combineis:
baseis:
(fun (h:int) (acc:int list) -> acc @ [h])
0
3. combineis:
baseis:
(fun (h:int) (acc:int list) -> acc @ [h])
[]
4. reversecan’tbewrittenbywithfold.
CIS120
Answer:3
FunctionsasData
• We’veseenanumberofwaysinwhichfunctionscanbe
treatedasdatainOCaml
• Everydayprogrammingpracticeoffersmanymoreexamples
–
–
–
–
objectsbundle“functions”(a.k.a.methods)withdata
iterators (“cursors”forwalkingoverdatastructures)
eventlisteners(inGUIs)
etc.
• Alsoheavilyusedat“largescale”:Google’sMapReduce
– Frameworkfortransforming(mapping)setsofkey-valuepairs
– Then“reducing”theresultsperkeyofthemap
– Easilydistributedto10,000machinestoexecuteinparallel!
CIS120
AbstractCollections
Areyoufamiliarwiththeideaofaset from
mathematics?
1. yes
2. no
Inmath,wetypicallywritesetslikethis:
Ø{1,2,3}{true,false}
withoperations:
S⋃ Tforunionand
S⋂ Tforintersection;
wewritex ∈ Sfor
“x isamemberofthesetS”
CIS120
Asetisanabstraction
• Asetisacollectionofdata
– wehaveoperationsforformingsetsofelements
– wecanaskwhetherelementsareinaset
• Asetisalotlikealist,except:
– Orderdoesn'tmatter
– Duplicatesdon'tmatter
– Itisn'tbuiltintoOCaml
Anelement’spresence orabsenceinthe
setisallthatmatters…
• Setsshowupfrequentlyinapplications
– Examples:setofstudentsinaclass,setofcoordinatesina
graph,setofanswerstoasurvey,setofdatasamplesfrom
anexperiment,…
Abstracttype:set
• ABSTcanimplement(represent)a
set
– thereisawaytorepresentanemptyset
(Empty)
– thereisawaytolistallelementscontainedin
theset(inorder)
– thereisawaytotestmembership(lookup)
– Candefineunion/intersection(withinsert
anddelete)
• BSTs arenottheonlywayto
implementsets
1
<
>
0
3
concreterepresentation
abstractview
1
0
3
ThreeExampleRepresentationsofSets
BST:
1
<
>
0
3
concreterepresentation
abstractview
1
0
3
Alternaterepresentation:
unsortedlinkedlist.
3::0::1::[]
concreterepresentation
abstractview
1
0
3
Alternaterepresentation:
reversesortedarraywith
Indexofnextslot.
3
1
0
X
X
concreterepresentation
abstractview
1
0
3
Abstracttypes(e.g.set)
• Anabstracttypeisdefinedbyitsinterface
anditsproperties,notitsrepresentation.
• Interface: definesoperationsonthetype
?
– Thereisanemptyset
– Thereisawaytoaddelementstoasettomakeabigger
set
– Thereisawaytolistallelementsinaset
– Thereisawaytotestmembership
• Properties: definehowtheoperations
interactwitheachother
– Elementsthatwereaddedcanbefoundintheset
– Addinganelementasecondtimedoesn’tchangethe
elementsofaset
– Addinginadifferentorderdoesn’tchangetheelements
ofaset
• Any type(possiblywithinvariants)that
satisfiestheinterfaceandpropertiescanbe
aset.
concreterepresentation
abstractview
1
0
3
SetsinOCaml
Thenameofthesignature.
SetSignature
Thesig keywordindicates
aninterfacedeclaration
module type SET = sig
type 'a set
val
val
val
val
val
empty
add
member
equals
set_of_list
:
:
:
:
:
'a
'a
'a
'a
'a
Typedeclarationhasno
“right-handside”– its
representationisabstract!
set
-> 'a set -> 'a set
-> 'a set -> bool
set -> 'a set -> bool
list -> 'a set
end
Theinterfacemembersarethe(only!)
meansofmanipulatingtheabstracttype.
Signature(a.k.a.Interface): definesoperationsonthetype
Implementingsets
• Therearemanywaystoimplementsets.
– lists,trees,arrays,etc.
• Howdowechoosewhichimplementation?
– Dependsontheneedsoftheapplication…
– Howoftenis‘member’usedvs.‘add’?
– Howbigcanthesetsbe?
• Manysuchimplementationsareoftheflavor
“asetisa…withsomeinvariants”
–
–
–
–
Asetisalistwithnorepeatedelements.
Asetisatreewithnorepeatedelements
Asetisabinarysearchtree
Asetisanarrayofbits,where0=absent,1=present
• Howdowepreservetheinvariantsoftheimplementation?
Amoduleimplementsaninterface
• Animplementationofthesetinterfacewilllooklikethis:
Nameofthemodule
Signaturethatitimplements
Thestruct keywordindicates
amoduleimplementation
module BSTSet : SET = struct
…
(* implementations of all the operations *)
…
end
Implementtheset Module
module BSTSet : SET = struct
type 'a tree =
| Empty
| Node of 'a tree * 'a * 'a tree
type 'a set = 'a tree
let empty : 'a set = Empty
…
end
•
Modulemustdefine(givea
concreterepresentationto)the
typedeclaredinthesignature
Theimplementationhastoincludeeverythingpromisedbytheinterface
– Itcancontainmore functionsandtypedefinitions(e.g.auxiliaryorhelper
functions)butthosecannotbeusedoutsidethemodule
– Thetypesoftheprovidedimplementationsmustmatchtheinterface
Abstractvs.ConcreteBSTSet
s=
1
<
>
0
3
concreterepresentation
abstractview
1
0
3
module BSTSet : SET = struct
type 'a tree = …
type 'a set = 'a tree
let empty : 'a set = Empty
let add (x:'a) (s:'a set) :'a set=
... (* can treat s as a tree *)
end
module type SET = sig
type 'a set
val empty : 'a set
val add
: 'a -> 'a set -> 'a set
end
(* A client of the BSTSet module *)
;; open BSTSet
let s : int set
= add 0 (add 3 (add 1 empty))
AnotherImplementation
module ULSet : SET =
struct
type 'a set = 'a list
let empty : 'a set = []
…
end
Adifferentdefinitionfor
thetypeset
Abstractvs.ConcreteULSet
s
=
0::3::1::[]
concreterepresentation
abstractview
1
0
3
module ULSet : SET = struct
type 'a set = 'a list
let empty : 'a set = []
let add (x:'a) (s:'a set) :'a set=
x::s (* can treat s as a list *)
end
module type SET = sig
type 'a set
val empty : 'a set
val add
: 'a -> 'a set -> 'a set
end
(* A client of the ULSet module *)
;; open ULSet
let s : int set
= add 0 (add 3 (add 1 empty))
Clientcodedoesn’tchange!
CompletingULSet
Seesets.ml
Testing(andusing)sets
• Tousethevaluesdefinedinthesetmoduleusethe“dot”
syntax:
ULSet.<member>
• Note:ModulenamesmustbecapitalizedinOCaml
let s1 = ULSet.add 3 ULSet.empty
let s2 = ULSet.add 4 ULSet.empty
let s3 = ULSet.add 4 s1
let test () : bool = (ULSet.member 3 s1)
;; run_test "ULSet.member 3 s1" test
let test () : bool = (ULSet.member 4 s3)
;; run_test "ULSet.member 4 s3" test
Testing(andusing)sets
• Alternatively,use“open”tobringallofthenamesdefinedin
theinterfaceintoscope.
;; open ULSet
let s1 = add 3 empty
let s2 = add 4 empty
let s3 = add 4 s1
let test () : bool = (member 3 s1)
;; run_test "ULSet.member 3 s1" test
let test () : bool = (member 4 s3)
;; run_test "ULSet.member 4 s3" test
module type SET = sig
type 'a set
val empty : 'a set
val add
: 'a -> 'a set -> 'a set
end
Doesthiscodetypecheck?
module BSTSet : SET = struct
type 'a tree =
| Empty
| Node of 'a tree * 'a * 'a tree
type 'a set = 'a tree
let empty : 'a set = Empty
…
end
;; open BSTSet
let s1 : int set = add 1 empty
1. yes
2. no
Answer:yes
CIS120
module type SET = sig
type 'a set
val empty : 'a set
val add
: 'a -> 'a set -> 'a set
end
Doesthiscodetypecheck?
1. yes
2. no
module BSTSet : SET = struct
type 'a tree =
| Empty
| Node of 'a tree * 'a * 'a tree
type 'a set = 'a tree
let empty : 'a set = Empty
…
end
;; open BSTSet
let s1 = add 1 empty
let i1 = begin match s1 with
| Node (_,k,_) -> k
| Empty -> failwith “impossible”
end
Answer:no,addconstructsaset,notatree
CIS120
module type SET = sig
type 'a set
val empty : 'a set
val add
: 'a -> 'a set -> 'a set
end
Doesthiscodetypecheck?
module BSTSet : SET = struct
type 'a tree =
| Empty
| Node of 'a tree * 'a * 'a tree
type 'a set = 'a tree
let empty : 'a set = Empty
let size (t : 'a tree) : int = …
…
end
;; open BSTSet
let s1 = add 1 empty
let i1 = size s1
1. yes
2. no
Answer:no,cannotaccesshelperfunctionsoutsidethemodule
CIS120
module type SET = sig
type 'a set
val empty : 'a set
val add
: 'a -> 'a set -> 'a set
end
Doesthiscodetypecheck?
module BSTSet : SET = struct
type 'a tree =
| Empty
| Node of 'a tree * 'a * 'a tree
type 'a set = 'a tree
let empty : 'a set = Empty
…
end
;; open BSTSet
let s1 : int set = Empty
1. yes
2. no
CIS120
Answer:no,theEmptydata
constructorisnot
availableoutsidethemodule
Ifaclientmoduleworkscorrectlyandstartswith:
;; open ULSet
willitcontinuetoworkifwechangethatlineto:
;; open BSTSet
assumingthatULSet andBSTSet bothimplementSET
andsatisfyallofthesetproperties?
1. yes
2. no
Answer:yes(thoughperformancemaybedifferent)
CIS120
module type SET = sig
type 'a set
val empty : 'a set
val add
: 'a -> 'a set -> 'a set
val member : 'a -> 'a set -> bool
end
module BSTSet : SET = struct
type 'a tree =
| Empty
| Node of 'a tree * 'a * 'a tree
type 'a set = 'a tree
let empty : 'a set = Empty
…
end
Isispossibleforaclienttocallmember withatreethatis
notaBST?
1. yes
2. no
CIS120
No:theBSTSet operationspreservetheBSTinvariants.
thereisnowaytoconstructanon-BSTtreeusingthe
interface.
Abstracttypes
BIGIDEA:Hidetheconcrete representation ofatype
behindanabstractinterfacetopreserveinvariants
• Theinterfacerestrictshowotherpartsoftheprogramcan
interactwiththedata.
• Benefits:
– Safety: Theotherpartsoftheprogramcan’tbreakanyinvariants
– Modularity:Itispossibletochangetheimplementationwithout
changingtherestoftheprogram
Howcomfortabletoyoufeelwiththeconceptofan
invariant?
1.
2.
3.
4.
5.
CIS120
Totallyconfused(Ihavenoideawhattheyare)
Somewhatunsure(Icanonlygiveanexample)
It’sbeginningtomakesense
Prettyconfident(Iunderstandhowthey’reused)
I’vecompletelygotit(Icoulddesignmyown)
FiniteMapDemo
Usingmodulesignaturestopreserve
datastructureinvariants
finiteMap.ml
MotivatingScenario
• Supposeyouwerewritingsomecourse-management
softwareandneededtolookupthelabsectionfora
studentgiventhestudent’sPennKey?
– Studentsmightadd/dropthecourse
– Studentsmightswitchlabsections
– Studentsshouldbeinonlyonelabsection
• Howwouldyoudoit?Whatdatastructurewould
youuse?
CIS120
43
FiniteMaps
• Afinitemap(a.k.a.dictionary),isacollectionofbindings from
distinctkeys tovalues.
– Operationstoadd&removebindings,testforkeymembership,look
upavaluebyitskey
• Example:a(string, int) map mightmapaPennKey
tothelabsection.
– Themaptypeisgenericintwo arguments
• Likesets,finitemapsappearinmanysettings:
–
–
–
–
–
CIS120
mapdomainnamestoIPaddresses
mapwordstotheirdefinitions(adictionary)
mapusernamestopasswords
mapgamecharacteruniqueidentifierstodialogtrees
…
44
FiniteMapsignature
module type MAP = sig
type ('k,'v) map
val
val
val
val
val
val
val
end
empty
add
remove
mem
get
entries
equals
:
:
:
:
:
:
:
('k,'v) map
'k -> 'v -> ('k,'v) map -> ('k,'v) map
'k
-> ('k,'v) map -> ('k,'v) map
'k -> ('k,'v) map -> bool
'k -> ('k,'v) map -> ’v
('k,'v) map -> ('k * 'v) list
('k,'v) map -> ('k,'v) map -> bool
Summary:AbstractTypes
• Differentprogramminglanguageshavedifferentwaysof
lettingyoudefineabstracttypes
• Ataminimum,thismeansproviding:
– Awaytospecify(writedown)aninterface
– Ameansofhidingimplementationdetails(encapsulation)
• InOCaml:
– Interfacesarespecifiedusingasignatureorinterface
– Encapsulationisachievedbecausetheinterfacecanomit information
• typedefinitions
• namesandtypesofauxiliaryfunctions
– Clientscannotmentionvaluesortypesnotnamedintheinterface
BonusMaterial:OCaml Details
moduleandinterfacefiles
.mland.mlifiles
• You’vealreadybeenusingsignaturesandmodulesinOCaml.
• Aseriesoftypeandval declarationsstoredinafilefoo.mli
isconsideredasdefiningasignatureFOO
• Aseriesoftop-leveldefinitionsstoredinafilefoo.ml is
consideredasdefiningamoduleFoo
foo.mli
type t
val z : t
val f : t -> int
foo.ml
type t = int
let z : t = 0
let f (x:t) : int =
x + 1
test.ml
;; open Foo
;; print_int
(Foo.f Foo.z)
Files
module type FOO = sig
type t
val z : t
val f : t -> int
end
module Foo : FOO = struct
type t = int
let z : t = 0
let f (x:t) : int =
x + 1
end
module Test = struct
;; open Foo
;; print_int
(Foo.f Foo.z)
end
© Copyright 2026 Paperzz