diff options
author | Stuart Sierra <mail@stuartsierra.com> | 2009-06-23 12:12:14 -0400 |
---|---|---|
committer | Stuart Sierra <mail@stuartsierra.com> | 2009-06-23 12:12:14 -0400 |
commit | 0843c501a8720281d266b5b36b854a37b52b1bf9 (patch) | |
tree | 1efc54b3b2642da6733be4ac639e419b3ef1683d /src/clojure/contrib/template.clj | |
parent | 3cadf1436bcd69d4a001a650187e0e47806f5556 (diff) |
template.clj: removed old template namespace
Diffstat (limited to 'src/clojure/contrib/template.clj')
-rw-r--r-- | src/clojure/contrib/template.clj | 195 |
1 files changed, 0 insertions, 195 deletions
diff --git a/src/clojure/contrib/template.clj b/src/clojure/contrib/template.clj deleted file mode 100644 index f5049289..00000000 --- a/src/clojure/contrib/template.clj +++ /dev/null @@ -1,195 +0,0 @@ -;;; template.clj - anonymous functions that pre-evaluate sub-expressions - -;; By Stuart Sierra, http://stuartsierra.com/ -;; January 20, 2009 - -;; Copyright (c) Stuart Sierra, 2009. All rights reserved. The use -;; and distribution terms for this software are covered by the Eclipse -;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) -;; which can be found in the file epl-v10.html at the root of this -;; distribution. By using this software in any fashion, you are -;; agreeing to be bound by the terms of this license. You must not -;; remove this notice, or any other, from this software. - - - -;; CHANGE LOG -;; -;; January 20, 2009: added "template?" and checks for valid template -;; expressions. -;; -;; December 15, 2008: first version - - -;; DOCUMENTATION -;; -;; This file defines macros for using template expressions. These are -;; useful for writing macros. -;; -;; A template is an expression containing "holes" represented by the -;; symbols _1, _2, _3, and so on. ("_" is a synonym for "_1".) -;; -;; The "template" macro is similar to #(). It returns an anonymous -;; function containing the body of the template. Unlike #() or "fn", -;; however, any expressions that do not have any holes will be -;; evaluated only once, at the time the function is created, not every -;; time the function is called. -;; -;; Examples: -;; -(comment - ;; Assume we have some big, slow calculation. - (defn think-hard [] - (Thread/sleep 1000) - 1000) - - ;; With #(), think-hard gets called every time. - (time (doall (map #(+ % (think-hard)) - (range 5)))) - ;;=> "Elapsed time: 5001.33455 msecs" - ;;=> (1000 1001 1002 1003 1004) - - ;; With a template, think-hard only gets called once. - (time (doall (map (template (+ _ (think-hard))) - (range 5)))) - ;;=> "Elapsed time: 1000.907326 msecs" - ;;=> (1000 1001 1002 1003 1004) -) -;; -;; -;; There is also the do-template macro, which works differently. It -;; calls the same template multiple times, filling in values, and puts -;; it all inside a "do" block. It will split up the values based on -;; the number of holes in the template. -(comment - (do-template (foo _1 _2) :a :b :c :d) - ;; expands to: (do (foo :a :b) (foo :c :d)) - - (do-template (foo _1 _2 _3) 10 11 12 13 14 15) - ;; expands to: (foo 10 11 12) (foo 13 14 15) - ) - - - -(ns - #^{:author "Stuart Sierra", - :doc "Anonymous functions that pre-evaluate sub-expressions - - This file defines macros for using template expressions. These are - useful for writing macros. - - A template is an expression containing \"holes\" represented by the - symbols _1, _2, _3, and so on. (\"_\" is a synonym for \"_1\".) - - The \"template\" macro is similar to #(). It returns an anonymous - function containing the body of the template. Unlike #() or \"fn\", - however, any expressions that do not have any holes will be - evaluated only once, at the time the function is created, not every - time the function is called. - - Examples: - - Assume we have some big, slow calculation. - (defn think-hard [] - (Thread/sleep 1000) - 1000) - - With #(), think-hard gets called every time. - (time (doall (map #(+ % (think-hard)) - (range 5)))) - => \"Elapsed time: 5001.33455 msecs\" - => (1000 1001 1002 1003 1004) - - With a template, think-hard only gets called once. - (time (doall (map (template (+ _ (think-hard))) - (range 5)))) - => \"Elapsed time: 1000.907326 msecs\" - => (1000 1001 1002 1003 1004) - - There is also the do-template macro, which works differently. It - calls the same template multiple times, filling in values, and puts - it all inside a \"do\" block. It will split up the values based on - the number of holes in the template. - - (do-template (foo _1 _2) :a :b :c :d) - expands to: (do (foo :a :b) (foo :c :d)) - - (do-template (foo _1 _2 _3) 10 11 12 13 14 15) - expands to: (foo 10 11 12) (foo 13 14 15)"} - clojure.contrib.template - (:use clojure.contrib.walk)) - -(defn find-symbols - "Recursively finds all symbols in form." - [form] - (distinct (filter symbol? (tree-seq coll? seq form)))) - -(defn find-holes - "Recursively finds all symbols starting with _ in form." - [form] - (sort (distinct (filter #(.startsWith (name %) "_") - (find-symbols form))))) - -(defn find-pure-exprs - "Recursively finds all sub-expressions in form that do not contain - any symbols starting with _" - [form] - (filter #(and (list? %) - (empty? (find-holes %))) - (tree-seq seq? seq form))) - -(defn flatten-map - "Transforms a map into a vector like [key value key value]." - [m] - (reduce (fn [coll [k v]] (conj coll k v)) - [] m)) - -(defn template? - "Returns true if form is a valid template expression." - [form] - (if (seq (find-holes form)) true false)) - -(defmacro template - "Expands to a fn using _1, _2, _3, etc. as arguments (_ is the same - as _1). Any sub-expressions without any _* variables are evaluated - when the fn is created, not when it is called." - [& form] - (when-not (template? form) - (throw (IllegalArgumentException. (str (pr-str form) " is not a valid template.")))) - (let [form (postwalk-replace {'_ '_1} form) - holes (find-holes form) - pures (find-pure-exprs form) - smap (zipmap pures (repeatedly #(gensym "HOLE_"))) - newform (prewalk-replace smap form) - ;; Now, make sure we omit nested sub-expressions: - used (set (filter #(.startsWith (name %) "HOLE_") - (find-symbols newform))) - newmap (reduce (fn [m [k v]] (if (used v) (assoc m k v) m)) - {} smap)] - `(let ~(flatten-map (clojure.set/map-invert newmap)) - (fn ~(vec holes) - ~@newform)))) - -(defn apply-template - "Replaces _1, _2, _3, etc. in expr with corresponding elements of - values. Returns the modified expression. For use in macros." - [expr values] - (when-not (template? expr) - (throw (IllegalArgumentException. (str (pr-str expr) " is not a valid template.")))) - (let [expr (postwalk-replace {'_ '_1} expr) - holes (find-holes expr) - smap (zipmap holes values)] - (prewalk-replace smap expr))) - -(defmacro do-template - "Repeatedly evaluates template expr (in a do block) using values in - args. args are grouped by the number of holes in the template. - Example: (do-template (check _1 _2) :a :b :c :d) - expands to (do (check :a :b) (check :c :d))" - [expr & args] - (when-not (template? expr) - (throw (IllegalArgumentException. (str (pr-str expr) " is not a valid template.")))) - (let [expr (postwalk-replace {'_ '_1} expr) - argcount (count (find-holes expr))] - `(do ~@(map (fn [a] (apply-template expr a)) - (partition argcount args))))) |