Last active
November 14, 2015 14:32
-
-
Save ls0f/e3b072bcd5396bca32f0 to your computer and use it in GitHub Desktop.
python scheme interpreters http://norvig.com/lispy.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import math,operator as op | |
Number = (int, float) | |
Symbol = str | |
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) | |
def tokenize(text): | |
return text.replace("(", " ( ").replace(")", " ) ").split() | |
def atom(token): | |
try: | |
return int(token) | |
except ValueError: | |
try: | |
return float(token) | |
except ValueError: | |
return Symbol(token) | |
def read_from_tokens(tokens): | |
if len(tokens) == 0: | |
raise SyntaxError("error") | |
token = tokens.pop(0) | |
if token == '(': | |
L = [] | |
while tokens[0] != ')': | |
L.append(read_from_tokens(tokens)) | |
tokens.pop(0) | |
return L | |
if token == ')': | |
raise SyntaxError("error") | |
return atom(token) | |
def parse(text): | |
return read_from_tokens(tokenize(text)) | |
def init_env(): | |
env = Env() | |
env.update(vars(math)) # sin, cos, sqrt, pi, ... | |
env.update({ | |
'+':op.add, '-':op.sub, '*':op.mul, '/':op.div, | |
'>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq, | |
'abs': abs, | |
'append': op.add, | |
'apply': apply, | |
'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 | |
global_env = init_env() | |
def repl(prompt='pyscheme> '): | |
"A prompt-read-eval-print loop." | |
while True: | |
val = eval(parse(raw_input(prompt))) | |
print val | |
def eval(x, env=global_env): | |
"Evaluate an expression in an environment." | |
if isinstance(x, Symbol): # variable reference | |
return env.find(x)[x] | |
elif not isinstance(x, list): # constant literal | |
return x | |
elif x[0] == 'quote': # (quote exp) | |
(_, exp) = x | |
return exp | |
elif x[0] == 'if': # (if test conseq alt) | |
(_, test, conseq, alt) = x | |
return eval((conseq if eval(test, env) else alt), env) | |
elif x[0] == 'set!': # (set! var exp) | |
(_, var, exp) = x | |
env.find(var)[var] = eval(exp, env) | |
elif x[0] == 'define': # (define var exp) | |
(_, var, exp) = x | |
env[var] = eval(exp, env) | |
elif x[0] == 'lambda': # (lambda (var*) exp) | |
(_, vars, exp) = x | |
return lambda *args: eval(exp, Env(vars, args, env)) | |
elif x[0] == 'begin': # (begin exp*) | |
for exp in x[1:]: | |
val = eval(exp, env) | |
return val | |
else: # (proc exp*) | |
exps = [eval(exp, env) for exp in x] | |
proc = exps.pop(0) | |
return proc(*exps) | |
if __name__ == "__main__": | |
repl() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment