Upload
others
View
1
Download
0
Embed Size (px)
Citation preview
Func%onalProgramminginSchemeandLisp
Overview
• Inafunc(onalprogramminglanguage,func(onsarefirstclassobjects.
• Youcancreatethem,putthemindatastructures,composethem,specializethem,applythemtoarguments,etc.
• We’lllookathowfunc(onalprogrammingthingsaredoneinLisp
eval• Remember:Lispcodeisjustans‐expression
• YoucancallLisp’sevalua(onprocesswiththeevalfunc(on.
(defines(list‘cadr’(onetwothree))) s (CADR'(ONETWOTHREE))>(evals)
TWO>(eval(list'cdr(car'((quote(a.b))c))))B
Apply• Applytakesafunc(onandalistofargumentsforit,andreturnstheresultofapplyingthefunc(ontothearguments:
>(apply+‘(123))6
• Itcanbegivenanynumberofarguments,solongasthelastisalist:
>(apply+12‘(345))15
• Asimpleversionofapplycouldbewri]enas(define(applyflist)(eval(consflist)))
Lambda
• Thedefinespecialformcreatesafunc(onandgivesitaname.
• However,func(onsdon’thavetohavenames,andwedon’tneeddefinetodefinethem.• Wecanrefertofunc(onsliterallybyusingalambdaexpression.
Lambdaexpression• Alambdaexpressionisalistcontainingthesymbollambda,followedbyalistofparameters,followedbyabodyofzeroormoreexpressions:
>(definef(lambda(x)(+x2)))
>f
#<proceedure:f>
>(f100)
102
Lambdaexpression• Alambdaexpressionisaspecialform• Whenevaluated,itcreatesafunc(onandreturnsareferencetoit
• Thefunc(ondoesnothaveaname• alambdaexpressioncanbethefirstelementofafunc(oncall:>((lambda(x)(+x100))1)101
• Otherlanguageslikepythonandjavascripthaveadoptedtheidea
definevs.define
(define(add2x)(+x2))
(defineadd2(lambda(x)(+x2)))
(defineadd2#f)
(set!add2(lambda(x)(+x2)))
• The define special form comes in two varieties
• The three expressions to the right are entirely equivalent
• The first define form is just more familiar and convenient when defining a function
Mappingfunc%ons• CommonLispandSchemeprovidesseveralmappingfunc(ons• map(mapcarinLisp)isthemostfrequentlyused.• Ittakesafunc(onandoneormorelists,andreturnstheresultofapplyingthefunc(ontoelementstakenfromeachlist,un(loneofthelistsrunsout:
>(mapabs'(3‐42‐5‐6))(34256)>(mapcons'(abc)'(123))((a.1)(b.2)(c.3))>(map(lambda(x)(+x10))‘(123))(111213)>(maplist‘(abc)‘(1234))map:alllistsmusthavesamesize;argumentswere:#<procedure:list>(12)(abc)
Definingmap
• Definingasimple“oneargument”versionofmapiseasy
(define(map1funclist)(if(null?list)
null
(cons(func(firstlist))(map1func(restlist)))))
DefineLisp’sEveryandSome
• everyandsometakeapredicateandoneormoresequences• Whengivenjustonesequence,theytestwhethertheelementssa(sfythepredicate: (everyodd?‘(135)) #t (someeven?‘(123)) #t
• Ifgiven>1sequences,thepredicatetakesasmanyargsastherearesequencesandargsaredrawnoneata(mefromthem: (every>‘(135)‘(024)) #t
every
(define(everyflist)
;;notetheuseoftheandfunc(on
(if(null?list)
#t
(and(f(firstlist))
(everyf(restlist)))))
some
(define(someflist)
(if(null?list)
#f(or(f(firstlist))
(somef(restlist)))))
Willthiswork?
(define(someflist)
(not(every(lambda(x)(not(fx)))list)))
filter
(filter<f><list>)returnsalistoftheelementsof<list>whichsa(sfythepredicate<f>
>(filterodd?‘(012345))
(135)
>(filter(lambda(x)(>x98.6))
‘(101.198.698.199.4102.2))
(101.199.4102.2)
Example:filter(define(myfilterlistfunc);;returnsalistofelementsoflistwherefunc(onistrue
(cond((null?list)nil)((func(firstlist))(cons(firstlist)(myfilter(restlist)func)))(#t(myfilter(restlist)func))))
>(myfilter‘(1234567)even?)(246)
Example:filter• Defineintegersasafunc(onthatreturnsalistofintegersbetweenaminandmax
(define(integersminmax)(if(>minmax)empty(consmin(integers(add1min)max))))
• Andprime?asapredicatethatistrueofprimenumbersandfalseotherwise
>(filterprime?(integers220))(235711131719)
Here’sanotherpaJern• Weojenwanttodosomethinglikesumtheelementsofasequence
(define(sum‐listl)(if(null?l)
0(+(firstl)(sum‐list(restl)))))
• Andother(meswewanttheirproduct(define(mul(ply‐listl)
(if(null?l)1
(*(firstl)(mul(ply‐list(restl)))))
Here’sanotherpaJern• Weojenwanttodosomethinglikesumtheelementsofasequence
(define(sum‐listl)(if(null?l)
0(+(firstl)(sum‐list(restl)))))
• Andother(meswewanttheirproduct(define(mul(ply‐listl)
(if(null?l)1
(*(firstl)(mul(ply‐list(restl)))))
Example:reduce
Reducetakes(i)afunc(on,(ii)afinalvalue,and(iii)alist
Reduce(+0(v1v2v3…vn))isjustV1+V2+V3+…Vn+0
InScheme/Lispnota(on:>(reduce+0‘(12345))15
(reduce*1‘(12345))120
Example:reduce
(define(reducefunc(onfinallist)(if(null?list)
final
(func(on
(firstlist)
(reducefunc(onfinal(restlist)))))
Usingreduce(define(sum‐listlist);;returnsthesumofthelistelements
(reduce+0list))
(define(mul‐listlist)
;;returnsthesumofthelistelements
(reduce*1list))
(define(copy‐listlist)
;;copiesthetoplevelofalist(reducecons‘()list))
(define(append‐listlist)
;;appendsallofthesublistsinalist
(reduceappend‘()list))
Composingfunc%ons
>compose
#<procedure:compose>>(define(squarex)(*xx))>(define(doublex)(*x2))
>(square(double10))400>(double(square10))
200>(definesd(composesquaredouble))>(sd10)400
>((composedoublesquare)10)200
Here’showtodefineit
(define(my‐composef1f2)
(lambda(x)(f1(f2x))))
Variables,freeandbound
• Inthisfunc(on,towhatdoesthevariableGOOGOLrefer?
(define(big‐number?x);;returnstrueifxisareallybignumber
(>xGOOGOL))• ThescopeofthevariableXisjustthebodyofthefunc(onforwhichit’saparameter.
Here,GOOGOLisaglobalvariable
>(defineGOOGOL(expt10100))>GOOGOL
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
>(define(big‐number?x)(>xGOOGOL))
>(big‐number?(add1(expt10100)))
#t
WhichXisaccessedattheend?
>(defineGOOGOL(expt10100))
>GOOGOL10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
>(definex‐1)
>(define(big‐number?x)(>xGOOGOL))>(big‐number?(add1(expt10100)))#t
Variables,freeandbound
• Inthebodyofthisfunc(on,wesaythatthevariable(orsymbol)XisboundandGOOGOLisfree.
(define(big‐number?x)
;returnstrueifXisareallybignumber
(>XGOOGOL))
• Ifithasavalue,ithastobeboundsomewhereelse
Theletformcreateslocalvariables
>(let[(pi3.1415)(e2.7168)]
(big‐number?(exptpie)))
#f• Thegeneralformis(let<varlist>.<body>)• Itcreatesalocalenvironment,bindingthevariablestotheirini(alvalues,andevaluatestheexpressionsin<body>
Note: square brackets are line parens, but only match other square brackets. They are there to help you cope with paren fatigue.
Letcreatesablockofexpressions
(if(>ab)
(let()
(prins"aisbiggerthanb.~n")(prins"bissmallerthana.~n")
#t)#f)
Letisjustsyntac%csugarforlambda
(let[(pi3.1415)(e2.7168)](big‐number?(exptpie)))
((lambda(pie)(big‐number?(exptpie)))
3.1415
2.7168)
andthisishowwediditbackbefore~1973
Letisjustsyntac%csugarforlambda
Whathappenshere:
(definex2)
(let[(x10)(xx(*x2))]
(prins"xis~sandxxis~s.~n"xxx))
Letisjustsyntac%csugarforlambda
Whathappenshere:
(definex2)
((lambda(xxx)(prins"xis~sandxxis~s.~n"xxx))10
(*2x))
Letisjustsyntac%csugarforlambda
Whathappenshere:
(definex2)
(define(f000034xxx)(prins"xis~sandxxis~s.~n"xxx))
(f00003410(*2x))
letandlet*
• Theletspecialformevaluatesalloftheini(alvalueexpressions,andthencreatesanewenvironmentinwhichthelocalvariablesareboundtothem,“inparallel”
• Thelet*formdoesissequen(ally
• let*expandstoaseriesofnestedlets– (let*[(x100)(xx(*2x))](fooxxx))– (let[(x100)](let[(xx(*2x))](fooxxx)))
Whathappenshere?
>(defineX10)>(let[(X(*XX))](prins"Xis~s.~n"X)(set!X1000)(prins"Xis~s.~n"X)‐1)
???
>X
???
Whathappenshere?
>(defineX10) (let[(X(*XX))](prins“Xis~s\n”X)(set!X1000)(prins“Xis~s\n”X)‐1)
Xis100
Xis1000
‐1
>X10
Whathappenshere?
>(defineGOOGOL(expt10100))>(define(big‐number?x)(>xGOOGOL))
>(let[(GOOGOL(expt10101))]
(big‐number?(add1(expt10100))))
???
Whathappenshere?
>(defineGOOGOL(expt10100))>(define(big‐number?x)(>xGOOGOL))>(let[(GOOGOL(expt10101))](big‐number?(add1(expt10100))))#t• ThefreevariableGOOGOLislookedupintheenvironmentinwhichthebig‐number?Func(onwasdefined!
func%ons• Notethatasimpleno(onofafunc(oncangiveusthemachineryfor– Crea(ngablockofcodewithasequenceofexpressionstobeevaluatedinorder
– Crea(ngablockofcodewithoneormorelocalvariables
• Func(onalprogramminglanguageistousefunc(onstoprovideotherfamiliarconstructs(e.g.,objects)
• Andalsoconstructsthatareunfamiliar
Dynamicvs.Sta%cScoping
• Programminglanguageseitherusedynamicorsta(c(akalexical)scoping
• Inasta(callyscopedlanguage,freevariablesinfunc(onsarelookedupintheenvironmentinwhichthefunc(onisdefined
• Inadynamicallyscopedlanguage,freevariablesarelookedupintheenvironmentinwhichthefunc(oniscalled
Closures
• Lispisalexicallyscopedlanguage.• Freevariablesreferencedinafunc(onthosearelookedupintheenvironmentinwhichthefunc(onisdefined.Freevariablesarethoseafunc(on(orblock)doesn’tcreatescopefor.
• Aclosureisafunc(onthatrememberstheenvironmentinwhichitwascreated
• Anenvironmentisjustacollec(onofvariablebindingsandtheirvalues.
Closureexample>(define(make‐counter)(let((count0))(lambda()(set!count(add1count)))))>(definec1(make‐counter))>(definec2(make‐counter))>(c1)1>(c1)2>(c1)3>(c2)???
Afanciermake‐counter
Writeafanciermake‐counterfunc(onthattakesanop(onalargumentthatspecifiestheincrement>(defineby1(make‐counter))
>(defineby2(make‐counter2))>(definedecrement(make‐counter‐1))
>(by2)2
(by2)
4
Op%onalargumentsinScheme
(define(make‐counter.args);;argsisboundtoalistoftheactualargumentspassedtothe
func(on
(let[(count0)
(inc(if(null?args)1(firstargs)))]
(lambda()(set!count(+countinc)))))
KeywordargumentsinScheme
• Scheme,likeLisp,alsohasawaytodefinefunc(onsthattakekeywordarguments– (make‐counter)
– (make‐counter:ini(al100)– (make‐counter:increment‐1)– (make‐counter:ini(al10:increment‐2)• DifferentSchemedialectshaveintroduceddifferentwaystomixposi(onalarguments,op(onalarguments,defaultvalues,keywordargument,etc.
Closuretricks
Wecanwriteseveralfunc(onsthatareclosedinthesameenvironment,whichcanthenprovideaprivatecommunica(onchannel
(definefoo#f)
(definebar#f)
(let((secret‐msg"none"))(set!foo(lambda(msg)(set!secret‐msgmsg)))
(set!bar(lambda()secret‐msg)))
(display(bar));prints"none"(newline)
(foo”a]ackatdawn")(display(bar));prints”a]ackatdawn"