Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clojure deferred function execution

Ok Here is what i am trying to do

(defn addresses [person-id]
 ;addresses-retrival )

(defn person [id]
  (merge  {:addresses (addresses id)} {:name "john"}))

In the above person function i want addresses to be retrieved only on demand , like only when i do

(:addresses (person 10)) 

and not when

(person 10)

I am not sure if i am going about this right, being new to clojure.

like image 672
Surya Avatar asked Aug 22 '10 16:08

Surya


2 Answers

You can use delay.

(defn person [id]
  (delay  {:addresses (addresses id) :name "john"})) 

(person 2) will then return a delayed, without evaluating anything. To access the content and evaluate the delayed object, use force or deref (or @).

(:addresses @(person 5))

Alternatively, you can put the delay on the address only.

(defn person [id]
  {:addresses (delay (addresses id)) :name "john"})

which can be nicer depending on your problem.

It allows to define:

(defn get-address [person]
  @(:address person))

Which will get the delayed address and force it. (Forcing means computing the first time and retrieving the forced result any other times).

like image 73
Nicolas Oury Avatar answered Sep 21 '22 12:09

Nicolas Oury


At least as far as sequences go, clojure is pretty damned lazy without needed to be told.

Here, modelling your address-retrieval as counting, try:

(defn addresses [person-id]
  (iterate #(do (println %) (inc %)) person-id))

(defn person [id]
  (merge  {:addresses (addresses id)} {:name "john"}))

(def people (map person (range 100)))

So far it won't have printed anything, but if you say:

(doall (take 5 (:addresses (nth people 10))))

Then you should see the printing happen in exactly the cases that need to happen to count up five in the tenth place. I'd imagine that might be the sort of behaviour you want?

So get your address lookup to produce a lazy sequence (map, filter, reduce will all do)

like image 38
John Lawrence Aspden Avatar answered Sep 21 '22 12:09

John Lawrence Aspden