Created
July 20, 2012 08:40
-
-
Save alandipert/3149656 to your computer and use it in GitHub Desktop.
From Löb's Theorem to Spreadsheet Evaluation <http://blog.sigfpe.com/2006/11/from-l-theorem-to-spreadsheet.html>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (ns loeb | |
| "From Löb's Theorem to Spreadsheet Evaluation <http://blog.sigfpe.com/2006/11/from-l-theorem-to-spreadsheet.html>" | |
| (:use [clojure.walk :only (postwalk)])) | |
| (defn arg-trampoline | |
| "Like trampoline, but always invokes functions with the supplied | |
| arg. If f is not a function, it is returned without invocation." | |
| [f arg] | |
| (if (fn? f) | |
| (let [ret (f arg)] | |
| (if (fn? ret) | |
| (recur ret arg) | |
| ret)) | |
| f)) | |
| (defn tjuxt | |
| "Trampolining juxt. Like juxt, but each fn is trampolined using | |
| arg-trampoline." | |
| [& fns] | |
| (fn [argv] | |
| ((apply juxt (map #(partial arg-trampoline % argv) fns))))) | |
| (defn loeb | |
| ([coll] (loeb coll coll)) | |
| ([fns coll] ((apply tjuxt fns) coll))) | |
| (defn !! | |
| "Selector. Returns a function that takes an associative argument | |
| and returns the value at k." | |
| [k] | |
| #(get % k)) | |
| (defn & | |
| [f] | |
| (fn [& fns] | |
| (fn [coll] | |
| (apply f (loeb fns coll))))) | |
| (comment | |
| (loeb [7 (!! 0) ((& +) (!! 0) (!! 1))]) ; => [7 7 14] | |
| ;; Haskell: loeb [ (!!5), 3, (!!0) + (!!1), (!!2)*2, sum . take 3, 17] | |
| ;; Clojure: | |
| (loeb [(!! 5) | |
| 3 | |
| ((& +) (!! 0) (!! 1)) | |
| ((& *) (!! 2) 2) | |
| #(reduce + (loeb (take 3 %) %)) | |
| 17]) | |
| ;; => [17 3 20 40 40 17] | |
| ) | |
| ;;; | |
| ;;; Experimental sheet syntax | |
| ;;; | |
| (defn convert-form [form] | |
| (cond | |
| ;; convert field references to selector functions | |
| (and (symbol? form) (= (first (str form)) \_)) | |
| `(!! ~(Integer/parseInt (.substring (str form) 1))) | |
| ;; lift function calls | |
| (list? form) | |
| (let [[[_ op] & args] form] `((& ~op) ~@args)) | |
| ;; everything else becomes a constant function of itself | |
| :else | |
| `(constantly ~form))) | |
| (defn fn-idxs [v] | |
| (let [function? #(and (list? %) (= (first %) 'fn))] | |
| (keep-indexed #(when (function? %2) %1) v))) | |
| (defn mergev [v m] | |
| (reduce (fn [xs [k v]] (assoc xs k v)) v m)) | |
| (defmacro sheet [v] | |
| (let [idxs (fn-idxs v) | |
| fns (select-keys v idxs) | |
| without-fns (mergev v (zipmap idxs (repeat nil)))] | |
| `(loeb ~(mergev (second (postwalk convert-form without-fns)) fns)))) | |
| (comment | |
| (sheet [7 _0 (+ _0 _1)]) ;=> [7 7 14] | |
| ;; Haskell: loeb [ (!!5), 3, (!!0) + (!!1), (!!2)*2, sum . take 3, 17] | |
| ;; Clojure: | |
| (def sum #(reduce + %)) | |
| (sheet | |
| [_5, 3, (+ _0 _1), (* _2 2), (fn [s] (sum (loeb (take 3 s) s))), 17]) | |
| ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment