23/07/2016
(How to Write a (Lisp) Interpreter (in Python))
(HowtoWritea(Lisp)Interpreter(inPython))
Thispagehastwopurposes:todescribehowtoimplementcomputerlanguageinterpretersingeneral,andinparticular
[Link]
([Link]).Yearsago,[Link]
aroundthegoalistodemonstrate,asconciselyandaccessiblyaspossible,whatAlanKaycalled"Maxwell'sEquations
ofSoftware."
Whydoesthismatter?AsSteveYeggesaid,"Ifyoudon'tknowhowcompilerswork,thenyoudon'tknowhow
computerswork."Yeggedescribes8problemsthatcanbesolvedwithcompilers(orequallywithinterpreters,orwith
Yegge'stypicalheavydosageofcynicism).
SyntaxandSemanticsofSchemePrograms
Thesyntaxofalanguageisthearrangementofcharacterstoformcorrectstatementsorexpressionsthesemanticsis
[Link],inthelanguageofmathematicalexpressions(andin
manyprogramminglanguages),thesyntaxforaddingoneplustwois"1+2"andthesemanticsistheapplicationofthe
additionoperatortothetwonumbers,[Link]
itsvaluewewouldsaythat"1+2"evaluatesto3,andwritethatas"1+2"3.
[Link]:
Java
if ([Link]() > 0) {
fn(A[i] + 1,
return new String[] {"one", "two"});
}
Scheme
(if (> (val x) 0)
(fn (+ (aref A i) 1)
(quote (one two)))
Javahasawidevarietyofsyntacticconventions(keywords,infixoperators,threekindsofbrackets,operator
precedence,dotnotation,quotes,commas,semicolons),butSchemesyntaxismuchsimpler:
[Link]/expressiondistinction.
Numbers(e.g.1)andsymbols(e.g.A)[Link]
similartotheirJavacounterparts,exceptthatinScheme,operatorssuchas+and>aresymbolstoo.
[Link]"(",followedbyzeroormoreexpressions,followedbya")".The
firstelementofthelistdetermineswhatitmeans:
Aliststartingwithakeyword,e.g.(if ...),isaspecialformthemeaningdependsonthekeyword.
Aliststartingwithanonkeyword,e.g.(fn ...),isafunctioncall.
ThebeautyofSchemeisthatthefulllanguageonlyneedseightsyntacticforms.(Incomparison,Pythonhas110and
Javahas133.)Usingsomanyparenthesesmayseemunfamiliar,butithasthevirtuesofsimplicityandconsistency.
(Somehavejokedthat"Lisp"standsfor"LotsofIrritatingSillyParentheses"Ithinkitstandfor"LispIsSyntactically
Pure".)
InthispagewewillcoveralltheimportantpointsofScheme(omittingsomeminordetails),butwewilltaketwosteps
togetthere,definingasimplifiedlanguagefirst,beforedefiningthenearfullSchemelanguage.
Language1:LispyCalculator
LispyCalculatorisasubsetofSchemeusingonlyfivesyntacticforms(twoatomic,twospecialforms,andthe
procedurecall).LispyCalculatorletsyoudoanycomputationyoucoulddoonatypicalcalculatoraslongasyouare
[Link]:"if"
expressions,[Link]'sanexampleprogram,thatcomputestheareaofacircleofradius
10,usingtheformular2:
(begin
(define r 10)
(* pi (* r r)))
Hereisatableofalltheallowableexpressions:
Expression
[Link]
Syntax
SemanticsandExample
1/14
23/07/2016
(How to Write a (Lisp) Interpreter (in Python))
variable
reference
var
Asymbolisinterpretedasavariablenameitsvalueisthevariable'svalue.
Example:r10(assumingrwaspreviouslydefinedtobe10)
constant
literal
number
Anumberevaluatestoitself.
Examples:12 12or-3.45e+6 -3.45e+6
conditional (iftestconseqalt)
Evaluatetestiftrue,evaluateandreturnconseqotherwisealt.
Example:(if (> 10 20) (+ 1 1) (+ 3 3)) 6
definition (definevarexp)
Defineanewvariableandgiveitthevalueofevaluatingtheexpressionexp.
Examples:(define r 10)
procedure
(procarg...)
call
Ifprocisanythingotherthanoneofthesymbolsif, define, orquotethen
[Link],andthenthe
procedureisappliedtothelistofargvalues.
Example:(sqrt (* 2 8)) 4.0
IntheSyntaxcolumnofthistable,varmustbeasymbol,numbermustbeanintegerorfloatingpointnumber,andthe
[Link]...meanszeroormorerepetitionsofarg.
WhatALanguageInterpreterDoes
Alanguageinterpreterhastwoparts:
[Link]:Theparsingcomponenttakesaninputprogramintheformofasequenceofcharacters,verifiesit
accordingtothesyntacticrulesofthelanguage,[Link]
simpleinterpretertheinternalrepresentationisatreestructure(oftencalledanabstractsyntaxtree)thatclosely
[Link]
compilerthereisoftenaseriesofinternalrepresentations,startingwithanabstractsyntaxtree,andprogressingto
[Link]
thefunctionparse.
[Link]:Theinternalrepresentationisthenprocessedaccordingtothesemanticrulesofthelanguage,thereby
[Link]'sexecutionfunctioniscalledeval(notethisshadowsPython'sbuiltin
functionofthesamename).
Hereisapictureoftheinterpretationprocess:
program(str) parse abstractsyntaxtree(list) eval result(object)
Andhereisashortexampleofwhatwewantparseandevaltobeabletodo:
>> program = "(begin (define r 10) (* pi (* r r)))"
>>> parse(program)
['begin', ['define', 'r', 10], ['*', 'pi', ['*', 'r', 'r']]]
>>> eval(parse(program))
314.1592653589793
Parsing:parse,tokenizeandread_from_tokens
Parsingistraditionallyseparatedintotwoparts:lexicalanalysis,inwhichtheinputcharacterstringisbrokenupintoa
sequenceoftokens,andsyntacticanalysis,[Link]
tokensareparentheses,symbols,[Link](suchasMikeLeskandEric
Schmidt'slex),butwe'lluseaverysimpletool:Python'[Link]
charactersitaddsspacesaroundeachparen,[Link]:
def tokenize(chars):
"Convert a string of characters into a list of tokens."
return [Link]('(', ' ( ').replace(')', ' ) ').split()
>>> program = "(begin (define r 10) (* pi (* r r)))"
>>> tokenize(program)
['(', 'begin', '(', 'define', 'r', '10', ')', '(', '*', 'pi', '(', '*', 'r', 'r', ')', ')', ')']
Ourfunctionparsewilltakeastringrepresentationofaprogramasinput,calltokenizetogetalistoftokens,and
thencallread_from_tokenstoassembleanabstractsyntaxtree.read_from_tokenslooksatthefirsttokenifitisa
[Link]
2/14
23/07/2016
(How to Write a (Lisp) Interpreter (in Python))
')'that'[Link]'(',thenwestartbuildingupalistofsubexpressionsuntilwehitamatching')'.
[Link]'llletPythonmakethedistinctionbetweenthem:foreach
nonparentoken,firsttrytointerpretitasanint,thenasafloat,[Link]:
def parse(program):
"Read a Scheme expression from a string."
return read_from_tokens(tokenize(program))
def read_from_tokens(tokens):
"Read an expression from a sequence of tokens."
if len(tokens) == 0:
raise SyntaxError('unexpected EOF while reading')
token = [Link](0)
if '(' == token:
L = []
while tokens[0] != ')':
[Link](read_from_tokens(tokens))
[Link](0) # pop off ')'
return L
elif ')' == token:
raise SyntaxError('unexpected )')
else:
return atom(token)
def atom(token):
"Numbers become numbers; every other token is a symbol."
try: return int(token)
except ValueError:
try: return float(token)
except ValueError:
return Symbol(token)
parseworkslikethis:
>>> program = "(begin (define r 10) (* pi (* r r)))"
>>> parse(program)
['begin', ['define', 'r', 10], ['*', 'pi', ['*', 'r', 'r']]]
[Link]:
Symbol = str # A Scheme Symbol is implemented as a Python str
List = list # A Scheme List is implemented as a Python list
Number = (int, float) # A Scheme Number is implemented as a Python int or float
We'[Link].
Environments
Thefunctionevaltakestwoarguments:anexpression,x,thatwewanttoevaluate,andanenvironment,env,inwhich
[Link],evalwilluseaglobal
environentthatincludesthenamesforabunchofstandardfunctions(likesqrtandmax,andalsooperatorslike*).This
environmentcanbeaugmentedwithuserdefinedvariables,usingtheexpression(define variable value).Fornow,
wecanimplementanenvironmentasaPythondictof{variable:value}pairs.
import math
imoort operator as op
Env = dict # An environment is a mapping of {variable: value}
def standard_env():
"An environment with some Scheme standard procedures."
env = Env()
[Link](vars(math)) # sin, cos, sqrt, pi, ...
[Link]({
'+':[Link], '-':[Link], '*':[Link], '/':[Link],
'>':[Link], '<':[Link], '>=':[Link], '<=':[Link], '=':[Link],
'abs': abs,
'append': [Link],
'apply': apply,
'begin': lambda *x: x[-1],
'car': lambda x: x[0],
'cdr': lambda x: x[1:],
'cons': lambda x,y: [x] + y,
[Link]
3/14
23/07/2016
(How to Write a (Lisp) Interpreter (in Python))
'eq?': op.is_,
'equal?': [Link],
'length': len,
'list': lambda *x: list(x),
'list?': lambda x: isinstance(x,list),
'map': map,
'max': max,
'min': min,
'not': op.not_,
'null?': lambda x: x == [],
'number?': lambda x: isinstance(x, Number),
'procedure?': callable,
'round': round,
'symbol?': lambda x: isinstance(x, Symbol),
})
return env
global_env = standard_env()
Evaluation:eval
[Link],werepeatthetableofSchemeforms:
Expression
Syntax
SemanticsandExample
variable
reference
var
Asymbolisinterpretedasavariablenameitsvalueisthevariable'svalue.
Example:r10(assumingrwaspreviouslydefinedtobe10)
constant
literal
number
Anumberevaluatestoitself.
Examples:12 12or-3.45e+6 -3.45e+6
conditional (iftestconseqalt)
Evaluatetestiftrue,evaluateandreturnconseqotherwisealt.
Example:(if (> 10 20) (+ 1 1) (+ 3 3)) 6
definition (definevarexp)
Defineanewvariableandgiveitthevalueofevaluatingtheexpressionexp.
Examples:(define r 10)
procedure
(procarg...)
call
Ifprocisanythingotherthanoneofthesymbolsif, define, orquotethen
[Link],andthenthe
procedureisappliedtothelistofargvalues.
Example:(sqrt (* 2 8)) 4.0
Noticehowcloselythecodeforevalfollowsthetable:
def eval(x, env=global_env):
"Evaluate an expression in an environment."
if isinstance(x, Symbol): # variable reference
return env[x]
elif not isinstance(x, List): # constant literal
return x
elif x[0] == 'if': # conditional
(_, test, conseq, alt) = x
exp = (conseq if eval(test, env) else alt)
return eval(exp, env)
elif x[0] == 'define': # definition
(_, var, exp) = x
env[var] = eval(exp, env)
else: # procedure call
proc = eval(x[0], env)
args = [eval(arg, env) for arg in x[1:]]
return proc(*args)
We'redone!Youcanseeitallinaction:
>>> eval(parse("(define r 10)"))
>>> eval(parse("(* pi (* r r))"))
314.1592653589793
Interaction:AREPL
Itistedioustohavetoenter"eval(parse(...))"[Link]'sgreatlegaciesisthenotionofan
interactivereadevalprintloop:awayforaprogrammertoenteranexpression,andseeitimmediatelyread,evaluated,
[Link]
4/14
23/07/2016
(How to Write a (Lisp) Interpreter (in Python))
andprinted,withouthavingtogothroughalengthybuild/[Link]'sdefinethefunctionrepl(whichstands
forreadevalprintloop),andthefunctionschemestrwhichreturnsastringrepresentingaSchemeobject.
def repl(prompt='[Link]> '):
"A prompt-read-eval-print loop."
while True:
val = eval(parse(raw_input(prompt)))
if val is not None:
print(schemestr(val))
def schemestr(exp):
"Convert a Python object back into a Scheme-readable string."
if isinstance(exp, list):
return '(' + ' '.join(map(schemestr, exp)) + ')'
else:
return str(exp)
Hereisreplinaction:
>>> repl()
[Link]> (define r 10)
[Link]> (* pi (* r r))
314.159265359
[Link]> (if (> (* 11 11) 120) (* 7 6) oops)
42
[Link]>
Language2:FullLispy
Wewillnowextendourlanguagewiththreenewspecialforms,givingusamuchmorenearlycompleteScheme
subset:
Expression
Syntax
quotation (quote exp)
SemanticsandExample
Returntheexpliterallydonotevaluateit.
Example:(quote (+ 1 2)) (+ 1 2)
assignment (set!varexp)
Evaluateexpandassignthatvaluetovar,whichmusthavebeenpreviously
defined(withadefineorasaparametertoanenclosingprocedure).
Example:(set! r2 (* r r))
procedure (lambda (var...)exp)
Createaprocedurewithparameter(s)namedvar...andexpasthebody.
Example:(lambda (r) (* pi (* r r)))
Thelambdaspecialform(anobscurenomenclaturechoicethatreferstoAlonzoChurch'slambdacalculus)createsa
[Link]:
[Link]> (define circle-area (lambda (r) (* pi (* r r)))
[Link]> (circle-area 10)
314.159265359
Theprocedurecall(circle-area 10)causesustoevaluatethebodyoftheprocedure,(* pi (* r r)),inan
environmentinwhichpiand*havethesameglobalvaluestheyalwaysdid,[Link],it
wouldn'[Link]?We
wouldn'[Link],wewanttoarrangefortheretobealocalvariable
namedrthatwecansetto10withoutworryingaboutinterferingwithanyothervariablethathappenstohavethesame
[Link],onewhichallowsforbothlocalandglobalvariables.
Theideaisthatwhenweevaluate(circle-area 10),wewillfetchtheprocedurebody,(* pi (* r r)),and
evaluateitinanenvironmentthathasrasthesolelocalvariable,[Link]
words,wewantanenvironmentthatlookslikethis,withthelocalenvironmentnestedinsidethe"outer"global
environment:
pi: 3.141592653589793
*: <built-in function mul>
...
r: 10
Whenwelookupavariableinsuchanestedenvironment,welookfirstattheinnermostlevel,butifwedon'tfindthe
[Link]
5/14
23/07/2016
(How to Write a (Lisp) Interpreter (in Python))
variablenamethere,wemovetothenextouterlevel.
Itisclearthatproceduresandenvironmentsareintertwined,solet'sdefinethemtogether:
class Procedure(object):
"A user-defined Scheme procedure."
def __init__(self, parms, body, env):
[Link], [Link], [Link] = parms, body, env
def __call__(self, *args):
return eval([Link], Env([Link], args, [Link]))
class Env(dict):
"An environment: a dict of {'var':val} pairs, with an outer Env."
def __init__(self, parms=(), args=(), outer=None):
[Link](zip(parms, args))
[Link] = outer
def find(self, var):
"Find the innermost Env where var appears."
return self if (var in self) else [Link](var)
global_env = standard_env()
Weseethateveryprocedurehasthreecomponents:alistofparameternames,abodyexpression,andanenvironment
thattellsuswhatnonlocalvariablesareaccessiblefromthebody.
Anenvironmentisasubclassofdict,[Link]:the
constructor__init__buildsanewenvironmentbytakingalistofparameternamesandacorrespondinglistof
argumentvalues,andcreatinganewenvironmentthathasthose{variable:value}pairsastheinnerpart,andalsorefers
[Link]:eithertheinner
oneoranouterone.
Toseehowtheseallgotogether,[Link]
changed:[Link](x)tofindatwhatlevelthevariablexexiststhenwecanfetchthevalueofx
fromthatlevel.(Theclausefordefinehasnotchanged,becauseadefinealwaysaddsanewvariabletotheinnermost
environment.)Therearetwonewclauses:forset!,wefindtheenvironmentlevelwherethevariableexistsandsetitto
[Link],wecreateanewprocedureobjectwiththegivenparameterlist,body,andenvironment.
def eval(x, env=global_env):
"Evaluate an expression in an environment."
if isinstance(x, Symbol): # variable reference
return [Link](x)[x]
elif not isinstance(x, List): # constant literal
return x
elif x[0] == 'quote': # quotation
(_, exp) = x
return exp
elif x[0] == 'if': # conditional
(_, test, conseq, alt) = x
exp = (conseq if eval(test, env) else alt)
return eval(exp, env)
elif x[0] == 'define': # definition
(_, var, exp) = x
env[var] = eval(exp, env)
elif x[0] == 'set!': # assignment
(_, var, exp) = x
[Link](var)[var] = eval(exp, env)
elif x[0] == 'lambda': # procedure
(_, parms, body) = x
return Procedure(parms, body, env)
else: # procedure call
proc = eval(x[0], env)
args = [eval(arg, env) for arg in x[1:]]
return proc(*args)
Toappreciatehowproceduresandenvironmentsworktogether,considerthisprogramandtheenvironmentthatgets
formedwhenweevaluate(account1 -20.00):
+:<builtinoperatoradd>
make-account: <a Procedure>
(define make-account
(lambda (balance)
(lambda (amt)
(begin (set! balance (+ balance amt))
balance))))
[Link]
balance: 100.00
amt: -20.00
6/14
23/07/2016
(How to Write a (Lisp) Interpreter (in Python))
(define account1 (make-account 100.00))
(account1 -20.00)
account1: <a Procedure>
Eachrectangularboxrepresentsanenvironment,andthecoloroftheboxmatchesthecolorofthevariablesthatare
newlydefinedintheenvironment.Inthelasttwolinesoftheprogramwedefineaccount1andcall(account1
-20.00)thisrepresentsthecreationofabankaccountwitha100dollaropeningbalance,followedbya20dollar
[Link](account1 -20.00),[Link]
[Link](green)[Link]
balanceisnotdefinedthere:wehavetolookatthegreenenvironment'souterenv,[Link],the
variable+isnotfoundineitherofthoseweneedtodoonemoreouterstep,totheglobal(red)[Link]
[Link](var)findsthe
rightenvironmentaccordingtolexicalscopingrules.
Let'sseewhatwecandonow:
>>> repl()
[Link]> (define circle-area (lambda (r) (* pi (* r r))))
[Link]> (circle-area 3)
28.274333877
[Link]> (define fact (lambda (n) (if (<= n 1) 1 (* n (fact (- n 1))))))
[Link]> (fact 10)
3628800
[Link]> (fact 100)
9332621544394415268169923885626670049071596826438162146859296389521759999322991
5608941463976156518286253697920827223758251185210916864000000000000000000000000
[Link]> (circle-area (fact 10))
4.1369087198e+13
[Link]> (define first car)
[Link]> (define rest cdr)
[Link]> (define count (lambda (item L) (if L (+ (equal? item (first L)) (count item (rest L))) 0)))
[Link]> (count 0 (list 0 1 2 3 0 0))
3
[Link]> (count (quote the) (quote (the more the merrier the bigger the better)))
4
[Link]> (define twice (lambda (x) (* 2 x)))
[Link]> (twice 5)
10
[Link]> (define repeat (lambda (f) (lambda (x) (f (f x)))))
[Link]> ((repeat twice) 10)
40
[Link]> ((repeat (repeat twice)) 10)
160
[Link]> ((repeat (repeat (repeat twice))) 10)
2560
[Link]> ((repeat (repeat (repeat (repeat twice)))) 10)
655360
[Link]> (pow 2 16)
65536.0
[Link]> (define fib (lambda (n) (if (< n 2) 1 (+ (fib (- n 1)) (fib (- n 2))))))
[Link]> (define range (lambda (a b) (if (= a b) (quote ()) (cons a (range (+ a 1) b)))))
[Link]> (range 0 10)
(0 1 2 3 4 5 6 7 8 9)
[Link]> (map fib (range 0 10))
(1 1 2 3 5 8 13 21 34 55)
[Link]> (map fib (range 0 20))
(1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765)
Wenowhavealanguagewithprocedures,variables,conditionals(if),andsequentialexecution(thebeginprocedure).
Ifyouarefamiliarwithotherlanguages,youmightthinkthatawhileorforloopwouldbeneeded,butScheme
[Link]"Schemedemonstratesthataverysmallnumberofrules
forformingexpressions,withnorestrictionsonhowtheyarecomposed,sufficetoformapracticalandefficient
programminglanguage."InSchemeyouiteratebydefiningrecursivefunctions.
HowSmall/Fast/Complete/GoodisLispy?
InwhichwejudgeLispyonseveralcriteria:
Small:Lispyisverysmall:117noncommentnonblanklines4Kofsourcecode.(Anearlierversionwasjust90
lines,buthadfewerstandardproceduresandwasperhapsabittooterse.)ThesmallestversionofmySchemein
[Link]
7/14
23/07/2016
(How to Write a (Lisp) Interpreter (in Python))
Java,Jscheme,[Link](SchemeinFifty
Kilobytes),[Link]
IthinkitmeetsAlanKay's1972claimthatyoucoulddefinethe"mostpowerfullanguageintheworld"in"a
pageofcode."(However,IthinkAlanmightdisagree,becausehewouldcountthePythoncompileraspartofthe
code,puttingmewelloverapage.)
bash$ grep "^\s*[^#\s]" [Link] | wc
117 497 4276
Fast:Lispycomputes(fact 100)[Link]'sfastenoughforme(althoughfarslowerthanmost
otherwaysofcomputingit).
Complete:[Link]:
Syntax:Missingcomments,quoteandquasiquotenotation,#literals,thederivedexpressiontypes(suchas
cond,derivedfromif,orlet,derivedfromlambda),anddottedlistnotation.
Semantics:Missingcall/ccandtailrecursion.
DataTypes:Missingstrings,characters,booleans,ports,vectors,exact/[Link]
actuallyclosertoSchemevectorsthantotheSchemepairsandliststhatweimplementwiththem.
Procedures:Missingover100primitiveprocedures:alltheonesforthemissingdatatypes,plussome
otherslikeset-car!andset-cdr!,becausewecan'timplementset-cdr!completelyusingPythonlists.
Errorrecovery:Lispydoesnotattempttodetect,reasonablyreport,[Link]
theprogrammertobeperfect.
Good:That'[Link].
TrueStory
Tobackuptheideathatitcanbeveryhelpfultoknowhowinterpreterswork,here'sastory.Waybackin1984Iwas
[Link],[Link],
troffhadnofacilityforforwardreferencestosymboliclabels:Iwantedtobeabletowrite"Aswewillseeonpage
@theoremx"andthenwritesomethinglike"@(settheoremx\n%)"intheappropriateplace(thetroffregister\n%
holdsthepagenumber).MyfellowgradstudentTonyDeRosefeltthesameneed,andtogetherwesketchedouta
[Link],itturnedoutthattheLispwehadatthetime
wasgoodatreadingLispexpressions,butsoslowatreadingcharacteratatimenonLispexpressionsthatourprogram
wasannoyingtouse.
[Link]
that,butheknewhowtowriteatinyCroutineforreadingandechoingthenonLispcharactersandlinkitintotheLisp
[Link]'tknowhowtodothatlinking,butIreasonedthatwritinganinterpreterforthistriviallanguage(allit
hadwassetvariable,fetchvariable,andstringconcatenate)waseasy,[Link],ironically,Tony
wroteaLispprogram(withonesmallroutineinC)becausehewasaCprogrammer,andIwroteaCprogrambecauseI
wasaLispprogrammer.
Intheend,webothgotourthesesdone(Tony,Peter).
TheWholeThing
Thewholeprogramishere:[Link].
FurtherReading
TolearnmoreaboutSchemeconsultsomeofthefinebooks(byFriedmanandFellesein,Dybvig,Queinnec,Harvey
andWrightorSussmanandAbelson),videos(byAbelsonandSussman),tutorials(byDorai,PLT,orNeller),orthe
referencemanual.
IalsohaveanotherpagedescribingamoreadvancedversionofLispy.
PeterNorvig
96Comments
[Link]
Recommend 134
[Link]
Share
Login
SortbyBest
8/14
23/07/2016
(How to Write a (Lisp) Interpreter (in Python))
Jointhediscussion
thedeemon6yearsago
Here'saRubyanalogin60lineswithaddedsupportofcontinuations(call/cc,famousSchemefeature):
[Link]
RequiresRuby1.8.x.
22
Reply Share
PeterNorvig
Mod >thedeemon6yearsago
Verynice!
9
Reply Share
tarpsocks>thedeemon5yearsago
[Link].
3
Reply Share
PeterNorvig>tarpsocks5yearsago
tarpsocks,Ithinkitisonlylackingclarityifyoudon'[Link],itisclear.
OnethingIwouldobjectto:call/ccshouldbearegularfunction,notaspecialform.
8
Reply Share
m00nlight223>thedeemon2yearsago
It'strickytosaytheinterpretersupportcall/ccsincetheimplementationusecallccoftheRubylanguage
Reply Share
LostProtocol6yearsago
[Link]'howtowritesimplelanguageinterpretersinpython'andreachedthispage(thankyou
google).Thisarticlehadtwoprofoundimpactsonme.1)Iunderstoodhowtowritelispinterpretersin
python(obvious)and2)[Link],
neverreally'getting'[Link]
[Link](notagain)andalsolearningLispwith
[Link],IwishPythonhadequivalentof(defmacro)oflisp.:)ThanksMr.
NorvigIwillbuyyourbookonArtificialIntelligenceto(somehow)supportthiswebpage:D.
15
Reply Share
Dave5yearsago
Chapter11ofthisbook[Link]
implementationofaminiSchemeinterpreter.(Thisproblemset,[Link]
thatinterpreter).
7
Reply Share
TimFinin6yearsago
[Link]
(quote())forthetheemptylist,asin(definex(cons1(cons2(quote())))),butthewaylistsworkinPython,(eq?
(quote())(quote()))[Link][]:
global_env['null']=[]
6
Reply Share
Sainamdar5yearsago
[Link]/exercisesinSICPwhile
commuting.
[Link]
5
Reply Share
[Link]
9/14
23/07/2016
(How to Write a (Lisp) Interpreter (in Python))
Sainamdar>Sainamdar5yearsago
HereisanothervariationinJavascriptthatseparatessyntacticanalysisfromexecution.
[Link]
2
Reply Share
affiszervmention>Sainamdar3yearsago
stringsdon'tseemtoworkonyourinterpreter
(="str""str")givesTypeError:[Link]
Reply Share
ShantanuInamdar>affiszervmention3yearsago
[Link]"bydesign".AsPeterNorvigwroteinthe
completenessevaluationofLispy,itismissingmanydatatypeslike"Missingstrings,characters,
booleans,ports,vectors,exact/inexactnumbers".
Reply Share
PatHayes6yearsago
[Link],whatwouldreallybeinterestingwouldbetoseehowmanylinesofcodeyouneedtodo
thisinsomethingthatdoesn'thavebuiltinrecursionandinwhichyouhavetodescribegarbagecollection.
Somethinglikeanassemblylanguage...
4
Reply Share
TheoD'Hondt>PatHayes6yearsago
Havealookat[Link]
trampolinesandgarbagecollection...Shouldmakeyouhappy.
4
Reply Share
an691>TheoD'Hondt5yearsago
HelloTheo,aretheslidesandpossiblyvideosoftheselecturesavailable?
PeterNorvig
Reply Share
Mod >PatHayes6yearsago
Exactly,Pat!Thatisadifferentchallenge,[Link]
methatthe"onepage"didthat,ratherthanrelyingonahostlanguagetodoit.(Ontheotherhand,the"one
page"didnotincludethedefinitionsofindividualprocedures,includingsyntacticprocedures.)
2
Reply Share
MikeParr>PatHayes4yearsago
Pat:LispKitlisp(originallybyHenderson),hasanimplementationinPascal,butitusesarraysforlist
storage,ratherthanrecords/structsquiteclosetoassembler.
1
Reply Share
Frakturfreund5yearsago
Thiscodelooksverynice,[Link]
isahighlevellanguage,[Link],isuggesttohavealookintoZozotez,aLisp
InterpeterinBrainfuck(whichisaridiculouslylowleveltoylanguage):
[Link]
3
Reply Share
PeterNorvig
Mod >Frakturfreund5yearsago
YouarerightwearerelyingonmanyfeaturesofPython:callstack,datatypes,garbagecollection,[Link]
[Link]
[Link]'[Link]
myPAIPbook.
[Link]
10/14
23/07/2016
(How to Write a (Lisp) Interpreter (in Python))
myPAIPbook.
3
Reply Share
Frakturfreund>PeterNorvig5yearsago
Thanksforthehint!Illputthebookonmychristmaslist:).
Reply Share
espin5yearsago
Veryniceandinspiring!
FYIthereisanicesmalllispimplementationinCfromPiumatra(aresearcherwithAlanKayatVPRI)
at[Link]
3
Reply Share
missingparen3yearsago
there'samissingclosingpareninbelowexample
>>program="(definearea(lambda(r)(*3.141592653(*rr)))"
itshouldbe
>>program="(definearea(lambda(r)(*3.141592653(*rr))))"
2
Reply Share
fishyrecondite3yearsago
Fabulous...!!
2
Reply Share
Reborn22665yearsago
HiPeter
[Link]
[Link],pleaseletmeknowandIwill
removethepost.
[Link]
Thanks.
2
Reply Share
PeterNorvig
Mod >Reborn22665yearsago
[Link].
4
Reply Share
Reborn2266>PeterNorvig5yearsago
[Link].:)
2
Reply Share
JukkaVlimaa6yearsago
[Link]'tconsbelambdax,y:[x]+[y]?
2
Reply Share
PeterNorvig
Mod >JukkaVlimaa6yearsago
Shouldn'tconsbelambdax,y:[x]+[y]?Mostlyno.I'mtryingtomakeitworkforthecasewhereyisalist
(possiblyempty)[Link],(cons1'(23))shouldbe(123),andifx=1andy=[2,3],then
[1]+[2,3]is[1,2,3],sothat's[x]+y.(Imakeitlist(y)ratherthanyjustincaseyisatuple,notalist.)
Istillcan'tdotheequivalentof(cons12),whichshouldyield(1.2)thatcan'tberepresentedinmy
approachtolists.
2
[Link]
Reply Share
11/14
23/07/2016
(How to Write a (Lisp) Interpreter (in Python))
RalphCorderoy6yearsago
[Link]"[Link](0)#popoff')'"bemoreclearasthefaster,smallerbytecode,
"deltokens[0]"sincetokens[0],returnedbypop(),isn'twanted.
2
Reply Share
PeterNorvig
Mod 6yearsago
[Link]:[Link]
necessarytohaveaccesstotheexptodotailrecursionelimination,butIdon'[Link]:you
[Link],whichcan'teasily
[Link]:IdidthisbecauseIstillgetalotofinterestinJScheme,and
[Link]:YesIcan!Massaro:youarerightthatamutable
[Link]
that,theywouldbedifferentfromPython'slists,andIcouldn'tusePython'smap,etc.
2
Reply Share
EricCooper6yearsago
Hereisamoremetacircularimplementationofprocedures:
defprocedure(parms,exp,env):
"AuserdefinedSchemeprocedure."
returnlambda*args:eval(exp,Env(parms,args,env))
2
Reply Share
PeterNorvig
Mod >EricCooper6yearsago
Thanks,[Link]'tuseitoriginallybecauseIwasthinkingaheadtoLispy2,
whereIcouldn'[Link],yoursuggestionisrighton.
Reply Share
KisituAugustine2yearsago
maybeammissingsomethinghere,whatdoes(_,vars,exp)=xmean??
1
Reply Share
steni>KisituAugustine2yearsago
Itmeansthatwhateverisinx,is"explodedinto"threevariables,ofwhichthefirstisdiscarded(becauseitis
notneeded).
Let'ssayxisanarray:x=[1,2,3].
Then(_,vars,exp)=xwilldiscardthe1,andnowvars=2,andexp=3.
Reply Share
KisituAugustine>steni2yearsago
thankssteni
Reply Share
cym133yearsago
GreatinterpretationofthatmagicalpartofSICP,happytoseethatthisbookstillinspirepeople!
1
Reply Share
[Link].
Konstantinos>Lolol3yearsago
What/prog/,aboardaboutprogramming,hastodowithLISP,aprogramminglanguage?
And/prog/asamatteroffactlikedLISPthoughnotmanyareusingit.
#Yes,fuckingrule14well,Ineverlikedfollowingtherulesanyway.
[Link]
12/14
23/07/2016
(How to Write a (Lisp) Interpreter (in Python))
Reply Share
Lulzy4yearsago
inallhonestythisiscrap
1
Reply Share
wang8monthsago
>(definecirclearea(lambda(r)(*pi(*rr)))
shouldbe
(definecirclearea(lambda(r)(*pi(*rr))))
Reply Share
wang8monthsago
[Link].
Reply Share
FloydLeeayearago
Ithinkschemegenerallyallowsmultipleexpressionsinlambdas,e.g.,localdefinitions.
Sointheevalfunction,thelambdacaseshouldbemorelike:
elif(ast[0]=='lambda'):
params=ast[1]
body=ast[2:]
returnProcedure(params,body,env)
andinProcedure:
def__call__(self,*args):
e=Env([Link],args,[Link])
foridx,exprinenumerate([Link]):
ifidx==len([Link])1:
returnmyeval(expr,e)
else:
myeval(expr,e)
Sorry,can'tseemtogetwhitespacetowork.
Reply Share
alexzhouayearago
verygood
Reply Share
Caridorcayearago
Ithasbeennicetoreadthis,clearlywritten,[Link].
Reply Share
marnout2yearsago
Brillant!
Reply Share
Eashan2yearsago
awesome
Reply Share
DivyanshPrakash3yearsago
[Link].
Reply Share
[Link]
13/14
23/07/2016
(How to Write a (Lisp) Interpreter (in Python))
Guest3yearsago
Howtotestaboveexamplesinpython2.7.5
Reply Share
victoracid3yearsago
Thatsremarkable...
Reply Share
affiszervmention3yearsago
howtodotailcalloptimization?
Reply Share
Loadmorecomments
Subscribe d AddDisqustoyoursiteAddDisqusAdd
[Link]
Privacy
14/14