Question

I struggle to understand a point in the code by Peter Norvig, 'Even better Python Lisp interpreter', here.

In eval function, aimed at parsing, he is doing the test isanstance(x,Symbol). Class Symbol is defined before, but it has no method, since it is declared with pass:

 class Symbol(str): pass

These lines build a symbol_table.

def Sym(s, symbol_table={}):
    "Find or create unique Symbol entry for str s in symbol table."
    if s not in symbol_table: symbol_table[s] = Symbol(s)
    return symbol_table[s]

_quote, _if, _set, _define, _lambda, _begin, _definemacro, = map(Sym, 
"quote   if   set!  define   lambda   begin   define-macro".split())

_quasiquote, _unquote, _unquotesplicing = map(Sym,
"quasiquote   unquote   unquote-splicing".split())

I don't understand why Symbol(s) is working, since no constructor for Symbol class has been defined. Afterwards, eval method checks whether the token is a Symbol the following way:

def eval(x, env=global_env):
     "Evaluate an expression in an environment."
      while True:
          if isa(x, Symbol):       # variable reference
              return env.find(x)[x]
          else: #other stuff

isa(x,Symbol) is a mystery. Here in code, should check whether token is a variable reference (that is x, with x that have been defined before). In my opinion, Symbol(s) here are a decoration for strings, in the initialization list built with

  _quote, _if, _set, _define, _lambda, _begin, _definemacro, = map(Sym, 
     "quote   if   set!  define   lambda   begin   define-macro".split())

Could you please explain based on your knowledge or reading of this code by P. Norvig or experience of Python? Thanks

Was it helpful?

Solution

Like all other methods, __init__ is inherited. Symbol inherits str's __init__.

Update: Note further that __init__ performs initialisation, not construction, and that initialisation code (with a slightly different effect) can also exist inside the class definition. This means that a valid object can exist without __init__ even needing to be called.

OTHER TIPS

The class definition of Symbol is just that it's a subclass of str. In other words, it's a string for most intents and purposes.

>>> class Symbol(str): pass
... 
>>> x=Symbol('abc')
>>> x
'abc'

It is a new class though, which means it will be treated a little differently by the interpreter:

>>> x == 'abc' # __eq__ is inherited
True
>>> x is 'abc' # different memory location from 'abc'
False
>>> y='abc'
>>> y is 'abc'
True

isa is a (rather unnecessary) redefinition of isinstance, which just checks if the variable is an instance of Symbol:

>>> isa = isinstance
>>> isa('abc', Symbol)
False
>>> isa(x, Symbol)
True
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top