Clojure: Transparently using delayed values

Clojure has a nice ‘(delay)’ macro which will delay the computation of anything you like.

(def lazy-val (delay (+ 1 2)))
lazy-val  ;; #<Delay@57d4f95b: :pending>
@lazy-val ;; 3
lazy-val  ;; #<Delay@57d4f95b: 3>

But, as you see above, you need to deref it with @ in order to get at the value on the inside. There are cases where this is a pain. You may have a chunk of code which already operates on regular values, and you want to provide a lazily computed value to it. As long as you’re using protocols, you’re good: you can extend-protocol on top of the Delay type to provide a version which is lazily constructed upon calling any of the protocol methods.

(defprotocol MyProto
(do-it [this]))</code>

(defrecord Impl [a b]
MyProto
(do-it [_] (+ a b)))

(extend-protocol MyProto
clojure.lang.Delay
(do-it [this] (do-it @this)))

(def lazy-instance (delay (->Impl 1 2)))

(do-it lazy-instance) ;; 3

This could probably be done more concisely with a macro, but I’m happy with this for now.

Advertisements