Help me write my LISP :) LISP environments, Ruby Hashes...
- by MikeC8
I'm implementing a rudimentary version of LISP in Ruby just in order to familiarize myself with some concepts. I'm basing my implementation off of Peter Norvig's Lispy (http://norvig.com/lispy.html).
There's something I'm missing here though, and I'd appreciate some help...
He subclasses Python's dict as follows:
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)
He then goes on to explain why he does this rather than just using a dict. However, for some reason, his explanation keeps passing in through my eyes and out through the back of my head.
Why not use a dict, and then inside the eval function, when a new "sub-environment" needs to be created, just take the existing dict and update the key/value pairs that need to be updated, and pass that new dict into the next eval?
Won't the Python interpreter keep track of the previous "outer" envs? And won't the nature of the recursion ensure that the values are pulled out from "inner" to "outer"?
I'm using Ruby, and I tried to implement things this way. Something's not working though, and it might be because of this, or perhaps not. Here's my eval function, env being a regular Hash:
def eval(x, env = $global_env)
........
elsif x[0] == "lambda" then
->(*args) { eval(x[2], env.merge(Hash[*x[1].zip(args).flatten(1)])) }
........
end
The line that matters of course is the "lambda" one.
If there is a difference, what's importantly different between what I'm doing here and what Norvig did with his Env class?
If there's no difference, then perhaps someone can enlighten me as to why Norvig uses the Env class. Thanks :)