Skip to content

Commit

Permalink
fix bugs in the lambda expression
Browse files Browse the repository at this point in the history
  • Loading branch information
onesuper committed Apr 10, 2015
1 parent d042004 commit 9c0babb
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 17 deletions.
57 changes: 42 additions & 15 deletions scheme/eval.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

from sexp import SExp, SSymbol, SInt, SBool, SAtom
from utils import html_spanize
from utils import html_spanize, num_to_ord_str
from prims import add_globals
from errors import EvalError

Expand All @@ -11,6 +11,10 @@

class Env(dict):
"""Environment"""

ident = ' '
newline = '\n'

def __init__(self, parms=(), args=(), outer=None):
self.update(zip(parms, args))
self.outer = outer
Expand All @@ -27,6 +31,20 @@ def find(self, var):
return self.outer.find(var) if self.outer else None


def to_pretty_str(self, depth=0):
"""
Recursively generate the environments.
Indented according to its depth.
"""

s = self.ident * depth
s += str(self)
s += self.newline
if self.outer:
for x in self.outer:
s += x.to_pretty_str(depth + 1)
return s


# def getOuterEnv(self):
# envStr = ""
Expand All @@ -37,6 +55,8 @@ def find(self, var):


def eval(sexp, env=add_globals(Env()), lv=0):
assert(isa(sexp, SExp)) # Only an object of SExp is evaluable

# evaluating values
if isa(sexp, SInt) or isa(sexp, SBool):
return sexp
Expand All @@ -48,46 +68,53 @@ def eval(sexp, env=add_globals(Env()), lv=0):
if e is None: raise EvalError('unbound variable')
return e[s]

# (quote exp)
# (quote body)
if sexp.children[0].value == 'quote':
if len(sexp.children) != 2:
raise EvalError('quote requires 1 argument')
(_, exp) = sexp.children
return exp
(_, sbody) = sexp.children
return sbody

# (define var exp)
# (define var body)
elif sexp.children[0].value == 'define':
if len(sexp.children) != 3:
raise EvalError('define requires 2 arguments')
(_, var, exp) = sexp.children
(_, svar, sbody) = sexp.children
e = Echo("define", lv)
e.ask("define a new variable %s and give it the value of %s" %
(html_spanize(var.to_lisp_str(), 'variable'),
html_spanize(exp.to_lisp_str(), 'body')))
env[var] = eval(exp, env, lv+1)
(html_spanize(svar.to_lisp_str(), 'variable'),
html_spanize(sbody.to_lisp_str(), 'body')))
env[svar.value] = eval(sbody, env, lv+1)
e.answer("define complete")

# (lambda params body)
elif sexp.children[0].value == 'lambda':
if len(sexp.children) != 3:
raise EvalError('lambda requires 2 arguments')
(_, params, exp) = sexp
(_, sparams, sbody) = sexp.children
e = Echo("lambda", lv)
e.ask("lambda creates a function with params %s, and %s as body" %
(html_spanize(params.to_lisp_str(), 'parameter'),
html_spanize(body.to_lisp_str()), 'body'))
(html_spanize(sparams.to_lisp_str(), 'parameter'),
html_spanize(sbody.to_lisp_str(), 'body')))

# construct the parameter list like: (a b c) and check the type
params = []
for i, param in enumerate(sparams.children):
if not isa(param, SSymbol):
raise EvalError('the %s parameter expected to be symbol') % num_to_ord_str(i)
params.append(param.value)

# create a anonymous function with Python's lambda function
# lv is passed via the last element of args
retval = lambda *args: eval(exp, Env(params, args, env), args[len(args)-1] + 1)
e.answer("function %s created", str(retval))
retval = lambda *args: eval(sbody, Env(params, args, env), args[len(args)-1] + 1)
e.answer("function %s created" % str(retval))
return retval

# (if test conseq alt)
elif sexp.children[0].value == 'if':
if len(sexp.children) != 4:
raise EvalError('if requires 3 arguments')
(_, test, conseq, alt) = x.children
(_, test, conseq, alt) = sexp.children
e0 = Echo("if", lv)
e0.ask("It depends...")
e = Echo("test", lv)
Expand Down
3 changes: 2 additions & 1 deletion scheme/prims.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ def add_globals(env):

def quit(lv):
import sys
sys.exit()
sys.exit()

5 changes: 5 additions & 0 deletions scheme/sexp.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ def to_lisp_str(self):
else: s += ')'
return s

def __repr__(self):
return 'sexp: '+ self.to_lisp_str()



def __str__(self, depth=0):
"""
Recursively generate a S-expression node.
Expand Down
2 changes: 1 addition & 1 deletion scheme/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def incr():
return count[0]
return incr

def ordinal(n):
def num_to_ord_str(n):
"""
Returns an ordinal number decorated string (e.g. '2nd')
@param n A integer number
Expand Down

0 comments on commit 9c0babb

Please sign in to comment.