/lazy-map-clojure

Create Clojure maps whose values are only calculated when accessed, either from data or from java objects.

Primary LanguageClojureEclipse Public License 1.0EPL-1.0

lazy-map https://secure.travis-ci.org/Malabarba/lazy-map-clojure.png?branch=master https://img.shields.io/badge/dryness-68-97CA00.svg https://coveralls.io/repos/Malabarba/lazy-map-clojure/badge.svg?branch=master&service=github

Create maps whose values are only calculated when accessed, either from data or from java objects. Supports both Clojure and Clojurescript!

https://clojars.org/malabarba/lazy-map/latest-version.svg

Documentation

This macro is analogous to lazy-seq. It takes a map (instead of a seq), but the value expressions you write aren’t actually evaluated until they are accessed.

user> (def my-map
        (lazy-map
         {:cause (do (println "Getting Cause")
                     :major-failure)
          :name (do (println "Getting Name")
                    "Some Name")}))
#'user/my-map

user> (:name my-map)
Getting Name
"Some Name"

user> (:name my-map)
"Some Name"

user> (:cause my-map)
Getting Cause
:major-failure

user> (:cause my-map)
:major-failure

You can also assoc new keys into a LazyMap like a regular Clojure map. If you assoc a delay it will act as a lazy value, and if you assoc anything else it acts as a regular value.

user> (def new-map (-> (assoc my-map :surname "Malabarba")
                 (assoc :delayed-surname
                        (delay (println "Resolved")
                               "Late Malabarba"))))
#'user/new-map
user> (:surname my-map)
"Malabarba"
user> (:delayed-surname my-map)
Resolved
"Late Malabarba"

The to-lazy-map protocol

This protocol allows you to convert any java class into a lazy map, where each entry correponds to a method call. Since everything is lazy, you can rest assured the methods won’t actually be called until you use them.

user> (use 'lazy-map.iop)
nil
user> (extend-lazy-map String)
nil

user> (to-lazy-map "My Own Map!")
{:to-char-array #object[clojure.lang.Delay 0x5c3c775a {:status :pending, :val nil}],
 :empty?        #object[clojure.lang.Delay 0x774f63f2 {:status :pending, :val nil}],
 :to-string     #object[clojure.lang.Delay 0x4a62ed8c {:status :pending, :val nil}],
 :intern        #object[clojure.lang.Delay 0x4ddc7018 {:status :pending, :val nil}],
 :chars         #object[clojure.lang.Delay 0x72e5585e {:status :pending, :val nil}],
 :class         #object[clojure.lang.Delay 0x7e39e503 {:status :pending, :val nil}],
 :length        #object[clojure.lang.Delay 0x236a69c5 {:status :pending, :val nil}],
 :trim          #object[clojure.lang.Delay 0xd988100 {:status :pending, :val nil}],
 :bytes         #object[clojure.lang.Delay 0x55671f45 {:status :pending, :val nil}],
 :code-points   #object[clojure.lang.Delay 0x64c7f917 {:status :pending, :val nil}],
 :to-lower-case #object[clojure.lang.Delay 0x1493800b {:status :pending, :val nil}],
 :hash-code     #object[clojure.lang.Delay 0x5d4a8318 {:status :pending, :val nil}],
 :object        #object[clojure.lang.Delay 0x30ba32c3 {:status :pending, :val nil}],
 :to-upper-case #object[clojure.lang.Delay 0x6b6e6a82 {:status :pending, :val nil}]}

user> (:to-upper-case *1)
"MY OWN MAP!"

Note how there’s an entry for each method. Obviously, only methods that takes no arguments (0-arity) are included.

There’s also an extra :object entry holding the string itself.

License

Copyright © 2015 Artur Malabarba

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.