From ebda2935b1ea9fed4c299c0141f9c40586bd4f9c Mon Sep 17 00:00:00 2001 From: Peter Norvig Date: Wed, 24 Oct 2018 15:09:42 -0700 Subject: [PATCH] Update lis.py --- py/lis.py | 120 +++++++++++++++++++++++------------------------------- 1 file changed, 51 insertions(+), 69 deletions(-) diff --git a/py/lis.py b/py/lis.py index 065eab4..f81376a 100644 --- a/py/lis.py +++ b/py/lis.py @@ -1,22 +1,60 @@ -################ Lispy: Scheme Interpreter in Python +################ Lispy: Scheme Interpreter in Python 3.3+ -## (c) Peter Norvig, 2010-16; See http://norvig.com/lispy.html +## (c) Peter Norvig, 2010-18; See http://norvig.com/lispy.html + +################ Imports and Types -from __future__ import division import math import operator as op - -try: - raw_input # Python 2 -except NameError: - raw_input = input # Python 3 - -################ Types +from collections import ChainMap as Environment Symbol = str # A Lisp Symbol is implemented as a Python str -List = list # A Lisp List is implemented as a Python list +List = list # A Lisp List is implemented as a Python list Number = (int, float) # A Lisp Number is implemented as a Python int or float +class Procedure(object): + "A user-defined Scheme procedure." + def __init__(self, parms, body, env): + self.parms, self.body, self.env = parms, body, env + def __call__(self, *args): + env = Environment(dict(zip(self.parms, args)), self.env) + return eval(self.body, env) + +################ Global Environment + +def standard_env(): + "An environment with some Scheme standard procedures." + env = {} + env.update(vars(math)) # sin, cos, sqrt, pi, ... + env.update({ + '+':op.add, '-':op.sub, '*':op.mul, '/':op.truediv, + '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq, + 'abs': abs, + 'append': op.add, + 'apply': lambda proc, args: proc(*args), + 'begin': lambda *x: x[-1], + 'car': lambda x: x[0], + 'cdr': lambda x: x[1:], + 'cons': lambda x,y: [x] + y, + 'eq?': op.is_, + 'equal?': op.eq, + 'length': len, + 'list': lambda *x: list(x), + 'list?': lambda x: isinstance(x,list), + 'map': lambda *args: list(map(*args)), + '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() + ################ Parsing: parse, tokenize, and read_from_tokens def parse(program): @@ -51,56 +89,12 @@ def atom(token): except ValueError: return Symbol(token) -################ Environments - -def standard_env(): - "An environment with some Scheme standard procedures." - env = Env() - env.update(vars(math)) # sin, cos, sqrt, pi, ... - env.update({ - '+':op.add, '-':op.sub, '*':op.mul, '/':op.truediv, - '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq, - 'abs': abs, - 'append': op.add, - 'apply': lambda proc, args: proc(*args), - 'begin': lambda *x: x[-1], - 'car': lambda x: x[0], - 'cdr': lambda x: x[1:], - 'cons': lambda x,y: [x] + y, - 'eq?': op.is_, - 'equal?': op.eq, - '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 - -class Env(dict): - "An environment: a dict of {'var':val} pairs, with an outer Env." - def __init__(self, parms=(), args=(), outer=None): - self.update(zip(parms, args)) - self.outer = outer - def find(self, var): - "Find the innermost Env where var appears." - return self if (var in self) else self.outer.find(var) - -global_env = standard_env() - ################ Interaction: A REPL def repl(prompt='lis.py> '): "A prompt-read-eval-print loop." while True: - val = eval(parse(raw_input(prompt))) + val = eval(parse(input(prompt))) if val is not None: print(lispstr(val)) @@ -111,21 +105,12 @@ def lispstr(exp): else: return str(exp) -################ Procedures - -class Procedure(object): - "A user-defined Scheme procedure." - def __init__(self, parms, body, env): - self.parms, self.body, self.env = parms, body, env - def __call__(self, *args): - return eval(self.body, Env(self.parms, args, self.env)) - ################ eval def eval(x, env=global_env): "Evaluate an expression in an environment." if isinstance(x, Symbol): # variable reference - return env.find(x)[x] + return env[x] elif not isinstance(x, List): # constant literal return x elif x[0] == 'quote': # (quote exp) @@ -138,9 +123,6 @@ def eval(x, env=global_env): elif x[0] == 'define': # (define var exp) (_, var, exp) = x env[var] = eval(exp, env) - elif x[0] == 'set!': # (set! var exp) - (_, var, exp) = x - env.find(var)[var] = eval(exp, env) elif x[0] == 'lambda': # (lambda (var...) body) (_, parms, body) = x return Procedure(parms, body, env)