Having found a nice post on how to built a simple lisp like (scheme like) language (How to Write a (Lisp) Interpreter (in Python)) I was wondering what would this look like in Clojure. Writing a lisp in Clojure sounded very useless and fun so here we go the result in on Github.
A couple interesting observations:
Since Clojure lends itself to using immutable datastructures the inital implementation of the evaluation seemed a little complex as it needs to receive the environment along with the next token. But as soon as I was implementing function calls this suddenly made the stacking of environments trivial. No complex chain maps etc. needed, nice!
clojure.core.match is a very nice little lib, I wish it was part of core Clojure by default. I had first implemented a giant cond statement, match made it much more concise and robust, as it not only asserts the matching symbol but also the parameters to it.
(defn lclj-eval "Eval a expression X in the context of environment ENV, defaults to base-env." ([x] (lclj-eval x lclj-base-env)) ([x env] (match [x] [(_ :guard symbol?)] {:result ((keyword x) env) :env env} [(_ :guard number?)] {:result x :env env} [['if _ _ _]] (lclj-eval (if-branch x env) env) [['define _ _]] {:env (define-in-env x env)} [['quote _]] {:env env :result (-> x rest first)} [['lambda _ _]] {:env env :result (lclj-fn x env)} :else (lclj-fn-call x env))))
Obviously this can all be done better but it was a fun (I guess in total) afternoon for sure, having never written a lisp interpreter before.