September 20, 2018
100 Days Of Clojure Code Day 6 - Make a Lisp - Part 2
I want to take a different approach today, and set up the simplest interpreter I can.
Here's one that Eric Normand shared on Apropos. We begin by defining some predicates for things that evaluate to themselves, like numbers and strings:
(defn my-eval [env expr]
(cond
(number? expr)
expr
(string? expr)
expr))
(my-eval {} 10)
(my-eval {} "yo")
Symbols get the value out of the env
:
(defn my-eval [env expr]
(cond
(number? expr)
expr
(string? expr)
expr
(symbol? expr)
(get env expr)))
(my-eval {'x 10} 'x)
Now lists, booleans and conditional logic:
(defn my-eval [env expr]
(cond
(number? expr)
expr
(string? expr)
expr
(boolean? expr)
expr
(symbol? expr)
(get env expr)
(list? expr)
(let [[op & args] expr]
(case op
'if
(let [[test then else] args]
(if (my-eval env test)
(my-eval env then)
(my-eval env else)))))))
(my-eval {} '(if true 10 20))
(my-eval {} '(if false 10 20))
Now function calls:
(defn my-eval [env expr]
(cond
(number? expr)
expr
(string? expr)
expr
(boolean? expr)
expr
(symbol? expr)
(get env expr)
(list? expr)
(let [[op & args] expr]
(case op
'if
(let [[test then else] args]
(if (my-eval env test)
(my-eval env then)
(my-eval env else)))
(let [[f & args](doall (map #(my-eval env %) expr))]
(apply f args))))))
(my-eval {'+ +} '(+ 1 2))
(my-eval {'+ +} '(+ 1 2 5))
(my-eval {'+ +} '(+ 1 2 5
(if true 10 0)))