clojure延迟函数执行
好的,这就是我要做的clojure延迟函数执行,clojure,lazy-evaluation,Clojure,Lazy Evaluation,好的,这就是我要做的 (defn addresses [person-id] ;addresses-retrival ) (defn person [id] (merge {:addresses (addresses id)} {:name "john"})) 在上面的person函数中,我希望只在需要时检索地址,就像只在需要时检索一样 (:addresses (person 10)) 而不是什么时候 (person 10) 作为clojure的新手,我不确定我是否正确地处理了
(defn addresses [person-id]
;addresses-retrival )
(defn person [id]
(merge {:addresses (addresses id)} {:name "john"}))
在上面的person函数中,我希望只在需要时检索地址,就像只在需要时检索一样
(:addresses (person 10))
而不是什么时候
(person 10)
作为clojure的新手,我不确定我是否正确地处理了这个问题。您可以使用延迟
(defn person [id]
(delay {:addresses (addresses id) :name "john"}))
(人员2)随后将返回延迟的,不进行任何评估的报告。
要访问内容并评估延迟对象,请使用force或deref(或@)
或者,您可以只在地址上设置延迟
(defn person [id]
{:addresses (delay (addresses id)) :name "john"})
根据你的问题,哪一个更好
它允许定义:
(defn get-address [person]
@(:address person))
这将获取延迟地址并强制执行。
(强制意味着第一次计算并在任何其他时间检索强制结果)。至少就序列而言,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))))
然后,你会看到印刷发生在需要发生的情况下,在第十位的五个。我想那可能是你想要的那种行为
因此,让您的地址查找生成一个惰性序列(映射、筛选、减少都可以)我可以建议一些接近您期望的内容
; 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)))
您可以从
地址函数返回一个函数,稍后调用该函数时将检索地址。大概是这样的:
(defn addresses [person-id]
#(;addresses-retrival))
(defn person [id]
(merge {:addresses ((addresses id))} {:name "john"}))
请注意,addresses
函数返回一个匿名函数(使用#
创建),而person
函数使用一对额外的参数调用该匿名函数。请记住,延迟会被记忆,因此,地址延迟的连续调用将始终产生与第一次取消延迟时相同的地址
(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.}
{:home 16 Cool St., :work 1243 Boring St.}
{:home 31 Cool St., :work 1243 Boring St.}
请注意家庭地址在延迟的第二个deref中是如何保持不变的
如果不希望出现这种行为,则需要使用函数闭包
(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 65 Cool St., :work 1243 Boring St.}
{:home 65 Cool St., :work 1243 Boring St.}
{:home 16 Cool St., :work 1243 Boring St.}
{:home 31 Cool St., :work 1243 Boring St.}
请注意,在随后的闭包调用中,家庭地址是如何不同的
所以,如果您是地址
函数会产生副作用,比如从数据库获取地址。这些人可以更改他们的地址,您希望您的代码始终具有最新的地址,如果延迟对您有效,或者函数关闭是更好的选择,请记住这一点。非常感谢。我想知道这是否可以透明化,以便在首次使用时对其进行评估。而不是手动强制评估?我不这么认为。据我所知,Clojure在懒惰和暴力方面表现得很明显。我的lazymap就是这样做的。它为所有贴图类型提供透明的下拉列表,只有在真正检索到它们时,才会计算它们的值。