(ns lccl.lc.evaluator (:import [lccl.lc.ast Var Abs App]) (:require [lccl.lc.ast :refer [->Abs ->App]])) (declare substitute) (defmulti evaluate (fn [term] [(type term)])) (defmethod evaluate [Var] ([term] term)) (defmethod evaluate [Abs] ([term] term)) (defmethod evaluate [App] ([term] (let [left (-> term :left)] (condp = (type left) Abs (substitute (:body left) (:arg left) (:right term)) term)))) (defmulti substitute (fn [body arg val] [(type body)])) (defmethod substitute [Var] ([body arg val] (if (= (:name body) arg) val body))) (defmethod substitute [Abs] ([body arg val] (if (= (:arg body) arg) body (->Abs (:arg body) (substitute (:body body) arg val))))) (defmethod substitute [App] ([body arg val] (->App (substitute (:left body) arg val) (substitute (:right body) arg val))))