Skip to content

Instantly share code, notes, and snippets.

@divs1210
Last active May 1, 2020 23:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save divs1210/ebe878a969486b3c0623b0881d2dc148 to your computer and use it in GitHub Desktop.
Save divs1210/ebe878a969486b3c0623b0881d2dc148 to your computer and use it in GitHub Desktop.
Futamura Projections in Clojure
(ns futamura
(:require [clojure.string :as str]))
;; ========= util =====================
(defn get-source-code [var]
(let [{:keys [file line]} (meta var)
file (slurp file)
lines (->> file
str/split-lines
(drop (dec line)))
text (str/join "\n" lines)]
(read-string text)))
(defn quoted [code]
(list 'quote code))
;; ====================================
(def Program
'(+ x y 3))
(defn Specializer
[code stat-in]
(case (first code)
'defn
(let [[_ _ argv & body] code
new-argv (->> argv
(remove #(contains? stat-in %))
vec)]
`(fn ~new-argv
(let [~@(for [kv stat-in
x kv]
x)]
~@body)))
;; else
`(let [~@(for [kv stat-in
x kv]
x)]
~code)))
(Specializer Program '{x 1})
;; => (let [x 1] (+ x y 3))
(Specializer '(defn add [x y]
(+ x y))
'{x 1})
;; => (fn [y] (let [x 1] (+ x y)))
(defn Interpreter
[code dyn-in]
(eval (Specializer code dyn-in)))
(Interpreter Program '{x 1 y 2})
;; => 6
;; First Projection
;; ================
(def P-Compiled-Source
(Specializer (get-source-code #'Interpreter)
{'code (quoted Program)}))
P-Compiled-Source
;; => (fn [dyn-in] (let [code '(+ x y 3)] (eval (Specializer code dyn-in))))
(def P-Compiled
(eval P-Compiled-Source))
(P-Compiled '{x 1 y 2})
;; => 6
;; Second Projection
;; =================
(def Compiler-Source
(Specializer (get-source-code #'Specializer)
{'code (quoted (get-source-code #'Interpreter))}))
(let [compiler (eval Compiler-Source)
p-compiled-source (compiler {'code (quoted Program)})
p-compiled (eval p-compiled-source)]
(p-compiled '{x 1 y 2}))
;; => 6
;; Third Projection
;; ================
(def Compiler-Compiler-Source
(let [specializer-source (get-source-code #'Specializer)]
(Specializer specializer-source
{'code (quoted specializer-source)})))
(let [compiler-compiler (eval Compiler-Compiler-Source)
interpreter-source (get-source-code #'Interpreter)
compiler-source (compiler-compiler {'code (quoted interpreter-source)})
compiler (eval compiler-source)
p-compiled-source (compiler {'code (quoted Program)})
p-compiled (eval p-compiled-source)]
(p-compiled '{x 1 y 2}))
;; => 6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment