Just a bit more playing with the Lispy Calculator to while away a few minutes in the afternoon.

I believe that I’m only missing the `if` function from my eval, along with a lot of functions that show up in the environment. Let’s create a test.

``````        _:test("if", function()
local prog = "(if (< 5 10) 10 20)"
local result = LISP:eval(LISP:parse(prog))
_:expect(result).is(10)
end)
``````

This is going to barf on the `if` and on the `<`.

``````9: if -- LISPCalc:53: No such symbol as Symbol if
``````
``````    elseif x[1].token == 'if' then
_ignored,test,conseq,alt = table.unpack(x)
local exp = self:eval(test,env) and conseq or alt
return self:eval(exp,env)
``````

We evaluate the conditional (test) and then select which of the consequent and alternative to evaluate. `if` guarantees to evaluate only the chosen expression.

Now I imagine I’ll find < not to work.

``````9: if -- LISPCalc:53: No such symbol as Symbol <
``````

So far so good. Put that into the environment.

``````    tab["<"] = function(a,b) return a<b end
``````

I rather imagine that this will work. And it does. Life is good. Extend the test to a few more operators.

``````            prog = "(if (> 5 10) 10 20)"
result = LISP:eval(LISP:parse(prog))
_:expect(result).is(20)
``````

Test will fail for want ot `>`. Providing that should make it green. And it does. Commit: if works. Added < and >.

Let’s do some more comparators and such. I feel as if I should test them all.

``````            result = LISP:exec("(if (<= 5 5) 1 0)")
_:expect(result).is(1)
result = LISP:exec("(if (<= 5 4) 1 0)")
_:expect(result).is(0)
result = LISP:exec("(if (>= 5 5) 1 0)")
_:expect(result).is(1)
result = LISP:exec("(if (>= 4 5) 1 0)")
_:expect(result).is(0)
``````

I decided that I need this:

``````9: if -- Tests:87: attempt to call a nil value (method 'exec')
``````
``````function LISP:exec(prog)
return self:eval(self:parse(prog))
end
``````
``````9: if -- LISPCalc:53: No such symbol as Symbol <=
``````
``````    tab[">="] = function(a,b) return a>=b end
tab["<="] = function(a,b) return a<=b end
``````

Tests green. Commit: >= and <=. LISP:exec does parse+eval.

We need `=` and `eq?`.

``````            result = LISP:exec("(if (= 5 5) 1 0)")
_:expect(result).is(1)
result = LISP:exec("(if (eq? 5 5) 1 0)")
_:expect(result).is(1)
result = LISP:exec("(if (= 5 6) 1 0)")
_:expect(result).is(0)
result = LISP:exec("(if (eq? 5 6) 1 0)")
_:expect(result).is(0)
``````
``````    tab["="] = function(a,b) return a==b end
tab["eq?"] = function(a,b) return a==b end
``````

Commit: = and eq?

A more careful reading tells me that `eq?` is identity and `equals?` is whatever `=` and op.eq are in Python. I’m going to ignore that issue for now.

I’m wondering about `apply`, among other things that I find in Norvig’s environment:

``````import math
import operator as op

def standard_env() -> Env:
"An environment with some Scheme standard procedures."
env = Env()
env.update(vars(math)) # sin, cos, sqrt, pi, ...
env.update({
'>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
'abs':     abs,
'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_,
'expt':    pow,
'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),
'print':   print,
'procedure?': callable,
'round':   round,
'symbol?': lambda x: isinstance(x, Symbol),
})
return env

global_env = standard_env()
``````

I am wondering about List, cons, car, and cdr, not because I don’t know what they are but because I’m not sure what the Python means. Remind me to learn some Python one of these days.

Same with map. Is it mapcar? I think Scheme says `map` when Lisp says `mapcar`. I think all that wants to wait until tomorrow, when I’ll mess with `list`. That should open up what `apply` and `map` are good for.

I really wish Norvig had provided some tests. It would help someone whose Lisp experience was before most of you were born. I’m a bit rusty.

Anyway, this was fun. See you next time!