Top Banner
CS 360 Programming Languages Day 13 – Dynamic Scope, Closure Idioms
31

CS 360 Programming Languages Day 13 –Dynamic Scope ...

Dec 12, 2021

Download

Documents

dariahiddleston
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: CS 360 Programming Languages Day 13 –Dynamic Scope ...

CS360ProgrammingLanguagesDay13– DynamicScope,

ClosureIdioms

Page 2: CS 360 Programming Languages Day 13 –Dynamic Scope ...

Lexicalscopingvs dynamicscoping• Thealternativetolexicalscopingiscalleddynamicscoping.

• Inlexical(static)scoping,ifafunctionfreferencesanon-localvariablex,thelanguagewilllookforxintheenvironmentwherefwasdefined.

• Indynamicscoping,ifafunctionfreferencesanon-localvariablex,thelanguagewilllookforxintheenvironmentwherefwascalled.– Ifit'snotfound,willlookintheenvironmentthatcalledthefunctionthat

calledf(andsoon).

Page 3: CS 360 Programming Languages Day 13 –Dynamic Scope ...

Example• AssumewehaveaPython/C++-stylelanguage.

• Whatdoesthisprogramprintunderlexicalscoping?

– 5,5

• Whatdoesthisprogramprintunderdynamicscoping?

– 5,10

x = 5

def foo():print(x)

def bar():x = 10foo()

foo()bar()

Page 4: CS 360 Programming Languages Day 13 –Dynamic Scope ...

Whydowepreferlexicaloverdynamicscope?1. Functionmeaningdoesnotdependonvariablenamesused.

Example:Canrenamevariablesatwill,aslongasyouareconsistent.– Lexicalscope:guaranteedtohavenoeffects.

Dynamicscope:mightchangethefunctionmeaning.

Whentheanonymousfunctionthatf returnsiscalled,inlexicalscoping,wealwaysknowwherethevaluesofx andywillbe(whatframesthey'rein).Withdynamicscoping,xwillbesearchedforinthefunctionsthatcalledtheanonymousfunction,sowhoknowswhatframesthey'llbein.

(define (f x) (lambda (y) (+ x y)))

Page 5: CS 360 Programming Languages Day 13 –Dynamic Scope ...

Whydowepreferlexicaloverdynamicscope?1. Functionmeaningdoesnotdependonvariablenamesused.

Example:Canremoveunusedvariablesinlexicalscoping.– Dynamicscope:Maychangemeaningofafunction(weird)

– Youwouldneverwritethisinalexically-scopedlanguage,becausethebindingofxto3isneverused.• (Nowayforgtoaccessthisparticularbindingofx.)

– Inadynamically-scopedlanguage,functiongmightrefertoanon-localvariablex,andthisbindingmightbenecessary.

(define (f g)(let ((x 3))(g 2)))

Page 6: CS 360 Programming Languages Day 13 –Dynamic Scope ...

Whydowepreferlexicaloverdynamicscope?2.Easytoreasonaboutfunctionswherethey'redefined.

Example:Dynamicscopetriestoaddastringtoanumber(b/cinthecallto(+xy),xwillbe"hello")

Inlexicalscope,wealwaysknowwhatfunctionfdoesevenbeforetheprogramiscompiledorrun.

(define x 1)

(define (f y) (+ x y))

(define (g) (let ((x "hello"))(f 4))

Page 7: CS 360 Programming Languages Day 13 –Dynamic Scope ...

Whydowepreferlexicaloverdynamicscope?3. Closurescaneasilystorethedatatheyneed.

– Manymoreexamplesandidiomstocome.

• Theanonymousfunctionreturnedbygteq referencesanon-localvariablex.

• Inlexicalscoping,theclosurecreatedfortheanonymousfunctionwillpointtogteq's framesoxcanbefound.

• Indynamicscoping,whoknowswhatxwouldbe.Makesitimpossibletousethisfunctionality.

(define (gteq x) (lambda (y) (>= y x)))(define (no-negs lst) (filter (gteq 0) lst))

Page 8: CS 360 Programming Languages Day 13 –Dynamic Scope ...

Whydoesdynamicscopeexist?• Lexicalscopeforvariablesisdefinitelytherightdefault.

– Verycommonacrosslanguages.

• Dynamicscopeisoccasionallyconvenientinsomesituations(e.g.,exceptionhandling).– Sosomelanguages(e.g.,Racket)havespecialwaystodoit.– Butmostdon’tbother.

• Historically,dynamicscopingwasusedmorefrequentlyinolderlanguagesbecauseit'seasiertoimplementthanlexicalscoping.– Strategy:Justsearchthroughthecallstackuntilvariableisfound.No

closuresneeded.– Callstackmaintainslistoffunctionsthatarecurrentlybeingcalled,so

mightaswelluseittofindnon-localvariables.

Page 9: CS 360 Programming Languages Day 13 –Dynamic Scope ...

Iteratorsmadebetter• Functionslikemap andfilter aremuchmorepowerfulthankstoclosures

andlexicalscope

• Functionpassedincanuseany“private”datainitsenvironment

• Iterator(e.g.,maporfilter)“doesn’tevenknowthedataisthere”– Itjustcallsthefunctionthatit'spassed,andthatfunctionwilltakecare

ofeverything.

(define (gteq x) (lambda (y) (>= y x)))(define (no-negs lst) (filter (gteq 0) lst))

Page 10: CS 360 Programming Languages Day 13 –Dynamic Scope ...

Moreidioms• Weknowtherulesforlexicalscopeandfunctionclosures.

– Nowwe'llseewhatit'sgoodfor.

Apartialbutwide-ranginglist:

• Passfunctionswithprivatedatatoiterators:Done• Currying(multi-arg functionsandpartialapplication)• Callbacks(e.g.,inreactive/event-drivenprogramming)• ImplementinganADT(abstractdatatype)witharecordoffunctions

Page 11: CS 360 Programming Languages Day 13 –Dynamic Scope ...

CurryingandPartialApplication• Curryingistheideaofcallingafunctionwith

anincompletesetofarguments.

• Whenyou"curry"afunction,yougetafunctionbackthatacceptstheremainingarguments.

• NamedafterHaskellCurry,whostudiedrelatedideasinlogic.– PLHaskellisnamedafterhim.

Page 12: CS 360 Programming Languages Day 13 –Dynamic Scope ...

CurryingandPartialApplication:Example• Weknow(expt x y) raisesx tothey'th power.• Wecoulddefineacurriedversionofexpt likethis:• (define (expt-curried x)

(lambda (y) (expt x y)))• Wecancallthisfunctionlikethis:

((expt-curried 4) 2)• Thisisusefulbecauseexpt-curried isnowafunctionofasingle

argumentthatcanmakeafamilyof"raise-this-to-some-power"functions.• Thisiscriticalinsomeotherfunctionallanguages(thoughnotRacketor

Scheme)wherefunctionsmayhaveatmostoneargument.

Page 13: CS 360 Programming Languages Day 13 –Dynamic Scope ...

CurryingandPartialApplication• CurryingisstillusefulinRacketwiththecurry function:

– Takesafunctionf and(optionally)someargumentsa1, a2, ….– Returnsananonymousfunctiong thataccumulatesargumentstof until

thereareenoughtocallf.

• (curry expt 4) returnsafunctionthatraises4toitsargument.– (curry expt 4) == expt-curried– ((curry expt 4) 2) == ((expt-curried 4) 2)

• (curry * 2) returnsafunctionthatdoublesitsargument.• Thesecanbeusefulindefinitionsthemselves:

– (define (double x) (* 2 x))– (define double (curry * 2))

Page 14: CS 360 Programming Languages Day 13 –Dynamic Scope ...

CurryingandPartialApplication• Curryingisalsousefultoshortenlongishlambdaexpressions:• Oldway:(map (lambda (x) (+ x 1)) '(1 2 3))• Newway:(map (curry + 1) '(1 2 3))

• Greatforencapsulatingprivatedata:(below,list-refisthebuilt-inget-nth.)

(define get-month (curry list-ref '(Jan Feb Mar Apr May Jun

Jul Aug Sep Oct Nov Dec)))

Page 15: CS 360 Programming Languages Day 13 –Dynamic Scope ...

CurryingandPartialApplication• Butthisgiveszero-basedmonths:• (define get-month

(curry list-ref '(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)))

• Let'ssubtractonefromtheargumentfirst:(define get-month (compose (curry list-ref '(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))

(curryr - 1)))

curryr curriesfromrighttoleft,ratherthanlefttoright.

Page 16: CS 360 Programming Languages Day 13 –Dynamic Scope ...

CurryingandPartialApplication• Afewmoreexamples:

• (map (compose (curry + 2) (curry * 4)) '(1 2 3))– quadruplesthenaddstwotothelist'(123)

• (filter (curry < 10) '(6 8 10 12))– Careful!curry worksfromtheleft,so(curry < 10) isequivalent

to(lambda (x) (< 10 x)) sothisfilterkeepsnumbersthataregreaterthan10.

• Probablyclearertodo:(filter (curryr > 10) '(6 8 10 12))

• (Inthiscase,theconfusionisbecauseweareusedto"<"beinganinfixoperator).

Page 17: CS 360 Programming Languages Day 13 –Dynamic Scope ...

ReturntothefoldrJCurryingbecomesreallypowerfulwhenyoucurryhigher-orderfunctions.

Recall(foldr f init (x1 x2 … xn)) returns(f x1 (f x2 … (f xn-2 (f xn-1 (f xn init))

(define (sum-list-ok lst) (foldr + 0 lst))

(define sum-list-super-cool (curry foldr + 0)

Page 18: CS 360 Programming Languages Day 13 –Dynamic Scope ...

Anotherexample• SchemeandRackethaveandmap andormap.• (andmap f (x1 x2…)) returns(and (f x1) (f x2) …)• (ormap f (x1 x2…)) returns(or (f x1) (f x2) …)

(andmap (curryr > 7) '(8 9 10)) è #t(ormap (curryr > 7) '(4 5 6 7 8)) è #t(ormap (curryr > 7) '(4 5 6)) è #f

(define contains7 (curry ormap (curry = 7)))(define all-are7 (curry andmap (curry = 7)))

Page 19: CS 360 Programming Languages Day 13 –Dynamic Scope ...

AnotherexampleCurryingandpartialapplicationcanbeconvenientevenwithouthigher-orderfunctions.Note:(range a b) returnsalistofintegersfromatob-1,inclusive.

(define (zip lst1 lst2)(if (null? lst1) '()

(cons (list (car lst1) (car lst2)) (zip (cdr lst1) (cdr lst2)))))

(define countup (curry range 1))

(define (add-numbers lst) (zip (countup (length lst)) lst))

Page 20: CS 360 Programming Languages Day 13 –Dynamic Scope ...

Whentousecurrying• Whenyouwritealambdafunctionoftheform

– (lambda (y1 y2 …) (f x1 x2 … y1 y2…))• Youcanreplacethatwith

– (curry f x1 x2 …)

• Similarly,replace– (lambda (y1 y2 …) (f y1 y2 … x1 x2…))

• with– (curryr f x1 x2 …)

Page 21: CS 360 Programming Languages Day 13 –Dynamic Scope ...

Whentousecurrying• Trythese:

– Assuminglst isalistofnumbers,writeacalltofilter thatkeepsallnumbersgreaterthan4.

– Assuminglst isalistoflistsofnumbers,writeacalltomap thataddsa1tothefrontofeachsublist.

– Assuminglst isalistofnumbers,writeacalltomap thatturnseachnumber(inlst)intothelist(1number).

– Assuminglst isalistofnumbers,writeacalltomap thatsquareseachnumber(youshouldcurryexpt).

– Defineafunctiondist-from-originintermsofcurryingafunction(distx1 y1 x2 y2) [assumedist isalreadydefinedelsewhere]

• Hint:Writeeachwithoutcurrying,thenreplacethelambdawithacurry.

Page 22: CS 360 Programming Languages Day 13 –Dynamic Scope ...

CallbacksAcommonidiom:Librarytakesfunctionstoapplylater,whenanevent occurs–examples:

– Whenakeyispressed,mousemoves,dataarrives– Whentheprogramenterssomestate(e.g.,turnsinagame)

Alibrarymayacceptmultiplecallbacks– Differentcallbacksmayneeddifferentprivatedatawithdifferenttypes– (CanaccomplishthisinC++withobjectsthatcontainprivatefields.)

Page 23: CS 360 Programming Languages Day 13 –Dynamic Scope ...

MutablestateWhileit’snotabsolutelynecessary,mutablestateisreasonablyappropriatehere

– Wereallydowantthe“callbacksregistered”and“eventsthathavebeendelivered”tochange duetofunctioncalls

In"pure"functionalprogramming,thereisnomutation.– Therefore,itisguaranteed thatcallingafunctionwithcertainarguments

willalwaysreturnthesamevalue,nomatterhowmanytimesit'scalled.– Notguaranteedoncemutationisintroduced.– Thisiswhyglobalvariablesareconsidered"bad"inlanguageslikeCor

C++(globalconstantsOK).

Page 24: CS 360 Programming Languages Day 13 –Dynamic Scope ...

Mutablestate:ExampleinC++times_called = 0

int function() { times_called++;return times_called;

}

Thisisuseful,butcancausebigproblemsifsomebodyelsemodifiestimes_called fromelsewhereintheprogram.

Page 25: CS 360 Programming Languages Day 13 –Dynamic Scope ...

Mutablestate• SchemeandRacket'svariablesaremutable.• Thenameofanyfunctionwhichdoesmutationcontainsa "!"• Mutateavariablewithset!

– Onlyworksafterthevariablehasbeenplacedintoanenvironmentwithdefine,let,orasanargumenttoafunction.

– set! doesnotreturnavalue.(define times-called 0)(define (function) (set! times-called (+ 1 times-called)) times-called)

• Noticethatfunctionsthathaveside-effectsorusemutationaretheonlyfunctionsthatneedtohavebodieswithmorethanoneexpressioninthem.

Page 26: CS 360 Programming Languages Day 13 –Dynamic Scope ...

ExampleRacketGUIwithcallback; Make a frame by instantiating the frame% class(define frame (new frame% (label "Example"))) ; Make a static text message in the frame(define msg (new message% (parent frame) (label "No events so far...")))

; Make a button in the frame(new button% (parent frame)(label "Click Me") (callback (lambda (button event)

(send msg set-label (number->string (function))))))

; Show the frame by calling its show method(send frame show #t)

Page 27: CS 360 Programming Languages Day 13 –Dynamic Scope ...

ExampleRacketGUIwithcallbackKeycode:

(new button% (parent frame)(label "Click Me") (callback (lambda (button event)

(send msg set-label (number->string (function))))))

(define times-called 0)(define (function) (set! times-called (+ 1 times-called)) times-called)

Page 28: CS 360 Programming Languages Day 13 –Dynamic Scope ...

AvoidclutteringtheglobalframeKeycode:

(new button% (parent frame2) (label "Click Me") (callback (let ((count-clicks 0))

(lambda (button event)(set! count-clicks (+ 1 count-clicks)) (send msg2 set-label

(number->string count-clicks))))))

Page 29: CS 360 Programming Languages Day 13 –Dynamic Scope ...

Howdoesthatwork?• Whatdoestheenvironmentdiagramfortheselooklike?

(define (f x)(let ((y 1))(lambda (y) (+ x y z))))

(define g(let ((x 1))(lambda (y) (+ x y))))

• Thisideaiscalledlet-over-lambda.Usedtomakelocalvariablesinafunctionthatpersistbetweenfunctioncalls.

Page 30: CS 360 Programming Languages Day 13 –Dynamic Scope ...

ImplementinganADTAsourlastpattern,closurescanimplementabstractdatatypes

– Theycansharethesameprivatedata– Privatedatacanbemutableorimmutable– Feelsquiteabitlikeobjects,emphasizingthatOOPandfunctional

programminghavesimilarities

Theactualcodeisadvanced/clever/tricky,buthasnonewfeatures– Combineslexicalscope,closures,andhigher-levelfunctions– Clientuseisnotsotricky

Page 31: CS 360 Programming Languages Day 13 –Dynamic Scope ...

(define (new-stack)(let ((the-stack '()))(define (dispatch method-name)(cond ((eq? method-name 'empty?) empty?)

((eq? method-name 'push) push)((eq? method-name 'pop) pop)(#t (error "Bad method name"))))

(define (empty?) (null? the-stack))(define (push item) (set! the-stack (cons item the-

stack)))(define (pop) (if (null? the-stack) (error "Can't pop an empty

stack")(let ((top-item (car the-stack)))(set! the-stack (cdr the-stack))top-item)))

dispatch)) ; this last line is the return value ; of the let statement at the top.