summaryrefslogtreecommitdiff
path: root/clojure/src/lccl/lc/evaluator.clj
diff options
context:
space:
mode:
Diffstat (limited to 'clojure/src/lccl/lc/evaluator.clj')
-rw-r--r--clojure/src/lccl/lc/evaluator.clj28
1 files changed, 28 insertions, 0 deletions
diff --git a/clojure/src/lccl/lc/evaluator.clj b/clojure/src/lccl/lc/evaluator.clj
new file mode 100644
index 0000000..70e972e
--- /dev/null
+++ b/clojure/src/lccl/lc/evaluator.clj
@@ -0,0 +1,28 @@
+(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))))