(def! bind-env (fn* [env b e] (if (empty? b) env (let* [b0 (first b)] (if (= '& b0) (assoc env (str (nth b 1)) e) (bind-env (assoc env (str b0) (first e)) (rest b) (rest e))))))) (def! new-env (fn* [& args] (if (<= (count args) 1) (atom {:outer (first args)}) (atom (apply bind-env {:outer (first args)} (rest args)))))) (def! env-find (fn* [env k] (env-find-str env (str k)))) (def! env-find-str (fn* [env ks] (if env (let* [data @env] (if (contains? data ks) env (env-find-str (get data :outer) ks)))))) (def! env-get (fn* [env k] (let* [ks (str k) e (env-find-str env ks)] (if e (get @e ks) (throw (str "'" ks "' not found")))))) (def! env-set (fn* [env k v] (do (swap! env assoc (str k) v) v)))