Commits

Meikel Brandmeyer  committed 2385fe5

A lazy map for Clojure (Initial check-in)

  • Participants

Comments (0)

Files changed (4)

+Copyright 2008 (c) Meikel Brandmeyer.
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

File lazy-map.clj

+;-
+; Copyright 2008 (c) Meikel Brandmeyer.
+; All rights reserved.
+;
+; Permission is hereby granted, free of charge, to any person obtaining a copy
+; of this software and associated documentation files (the "Software"), to deal
+; in the Software without restriction, including without limitation the rights
+; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+; copies of the Software, and to permit persons to whom the Software is
+; furnished to do so, subject to the following conditions:
+;
+; The above copyright notice and this permission notice shall be included in
+; all copies or substantial portions of the Software.
+;
+; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+; THE SOFTWARE.
+
+(clojure/in-ns 'lazy-map)
+(clojure/refer 'clojure)
+
+(defmacro lazy-map
+  "Lazy-map creates a map and returns a closure as function over the map's
+  keys. Each value is evaluated at most once."
+  [& kvs]
+  (loop [[k v & r :as kvs] kvs
+         lmap              {}]
+    (if (nil? kvs)
+      `(let [lmap# (ref ~lmap)
+             emap# (ref {})]
+         (fn [key#]
+           (or ((deref emap#) key#)
+               (let [lv# ((deref lmap#) key#)]
+                 (when-not (nil? lv#)
+                   (let [lve# (lv#)]
+                     (dosync
+                       (commute emap# assoc key# lve#)
+                       ; We dissoc the old value here to prevent a space leak.
+                       (commute lmap# dissoc key#))
+                     lve#))))))
+      (recur r `(assoc ~lmap ~k (fn [] ~v))))))

File t/000_lazy-map.t

+#(comment
+exec java clojure.lang.Script "$0" -- "$@"
+)
+;-
+; Copyright 2008 (c) Meikel Brandmeyer.
+; All rights reserved.
+;
+; Permission is hereby granted, free of charge, to any person obtaining a copy
+; of this software and associated documentation files (the "Software"), to deal
+; in the Software without restriction, including without limitation the rights
+; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+; copies of the Software, and to permit persons to whom the Software is
+; furnished to do so, subject to the following conditions:
+;
+; The above copyright notice and this permission notice shall be included in
+; all copies or substantial portions of the Software.
+;
+; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+; THE SOFTWARE.
+
+(load-file "tap.clj")
+(load-file "lazy-map.clj")
+(clojure/refer 'lazy-map)
+
+(tap/plan 8)
+
+(def counter (ref 0))
+
+(def lmap (lazy-map :foo (do (dosync (commute counter + 1)) :bar)
+                   :bar (do (dosync (commute counter + 1)) :foo)))
+
+(tap/is? (deref counter) 0 "the map values are not evaluated")
+
+(tap/is? (lmap :foo) :bar "the :foo key evaluates to the correct value")
+(tap/is? (deref counter) 1 "the counter is increased to 1")
+
+(tap/is? (lmap :bar) :foo "the :bar key evaluates to the correct value")
+(tap/is? (deref counter) 2 "the counter is increased to 2")
+
+(tap/is? (lmap :foo) :bar "the :foo key is still correct...")
+(tap/is? (deref counter) 2 "... but the counter is not increased anymore")
+
+(tap/ok? (nil? (lmap :baz)) "non-existent keys work also")
+
+(.exit java.lang.System 0)
+; vim:ft=clojure:
+
+  version.txt -- Version Information for lazy-map (syntax: Text)
+  [automatically generated and maintained by GNU shtool]
+
+  This is lazy-map, Version 1.0.0 (09-Jul-2008)
+