Подтвердить что ты не робот

Clojure выполнение отложенных функций

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

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

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

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

(:addresses (person 10)) 

а не когда

(person 10)

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

По крайней мере, насколько последовательности идут, 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))))

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

Итак, получите ваш адресный поиск, чтобы создать ленивую последовательность (карта, фильтр, уменьшить все будет)

Ответ 3

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

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

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

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

Ответ 4

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

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

Ответ 5

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

(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 работает для вас или если закрытие функции будет лучшим кандидатом.