выполнение отложенной функции clojure - PullRequest
12 голосов
/ 22 августа 2010

Хорошо. Вот что я пытаюсь сделать

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

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

В приведенной выше функции person я хочу, чтобы адреса извлекались только по требованию, например, только когда я делаю

(:addresses (person 10)) 

а не когда

(person 10)

Я не уверен, правильно ли я поступаю, будучи новичком в clojure.

Ответы [ 5 ]

10 голосов
/ 22 августа 2010

Вы можете использовать задержку.

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

(человек 2) вернет задержку, ничего не оценивая. Чтобы получить доступ к контенту и оценить задержанный объект, используйте force или deref (или @).

(:addresses @(person 5))

В качестве альтернативы вы можете указать задержку только для адреса.

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

, что может быть лучше в зависимости от вашей проблемы.

Позволяет определить:

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

Который получит задержанный адрес и заставит его. (Принудительное выполнение означает вычисление в первый раз и получение принудительного результата в любое другое время).

1 голос
/ 24 августа 2010

Вы можете вернуть функцию из функции addresses, которая при последующем вызове будет получать адреса. Как то так:

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

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

Обратите внимание, что функция addresses возвращает анонимную функцию (созданную с помощью #), а функция person вызывает эту анонимную функцию, используя дополнительную пару символов.

1 голос
/ 23 августа 2010

По крайней мере, что касается последовательности, clojure довольно чертовски ленив без необходимости говорить.

Здесь, моделируя ваш адресный поиск как подсчет, попробуйте:

(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)))

Пока ничего не напечатано, но если вы скажете:

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

Тогда вы должны увидеть, что печать происходит именно в тех случаях, когда это необходимо, чтобы сосчитать пять на десятом месте. Я полагаю, это может быть поведение, которое вы хотите?

Так что найдите свой адрес, чтобы получить ленивую последовательность (map, filter, lower все сделает)

0 голосов
/ 25 октября 2015

Помните, что Задержки запоминаются, поэтому последовательные вызовы с задержкой ваших адресов всегда будут давать тот же адрес, что и при первой отмене задержки.

(defn addresses [person-id]
  {:home (str (rand-int 100) " Cool St.") :work "1243 Boring St."})

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

(let [person1 (person 1)]
  (println @(:addresses person1))
  (println @(:addresses person1)))

При этом будет напечатано:

{:home 65 Cool St., :work 1243 Boring St.}
{:home 65 Cool St., :work 1243 Boring St.}

Обратите внимание, что домашний адрес не изменяется во второй раз задержке.

Если вы не хотите этого поведения, вам нужно вместо этого использовать закрытие функции.

(defn addresses [person-id]
  {:home (str (rand-int 100) " Cool St.") :work "1243 Boring St."})

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

(let [person1 (person 1)]
  (println ((:addresses person1)))
  (println ((:addresses person1))))

Это напечатает:

{:home 16 Cool St., :work 1243 Boring St.}
{:home 31 Cool St., :work 1243 Boring St.}

Обратите внимание, как домашний адрес отличался при последующем вызове на закрытие.

Итак, если вы addresses, функция имеет побочный эффектскажем, выбирает адреса из базы данных.И люди могут поменять свои адреса, и вы бы хотели, чтобы ваш код всегда имел самый последний адрес, об этом следует помнить, если у вас работает Delay или если лучшим вариантом будет закрытие функции.

0 голосов
/ 24 августа 2010

Я могу предложить что-то близкое к тому, что вы ожидаете.

; Note the use of anonymouns function. #(addresses id)
(defn person [id] 
  (merge  {:addresses #(addresses id)} {:name "john"}))

; :addresses returns a function. Evaluate it by wrapping it in another set of parans.
((:addresses (person 10)))
...