我非常喜欢这个问题。也许我很惊讶看到一个如此简单的新问题。无论如何,流口水,我想我有一些对你有用的东西。
而不是这样做:
(if (or @future1 @future2)
...)
做:
(if (or (and (realized? future1) @future1)
(and (realized? future2) @future2))
...)
诀窍是在询问它是否是true
或之前测试是否已实现false
。
这可以概括为这样的宏:
(defmacro future-or [& futures]
`(or ~@(for [f futures]
`(and (realized? ~f)
(deref ~f)))))
然后像这样使用:
(if (future-or future1 future2)
...)
等一等。也许我不正确地理解你的问题。也许您想阻止执行,直到其中一个期货完成并返回true
,在这种情况下您执行您的 then 子句if
,或者您的两个期货都完成并且都不返回true
,在这种情况下您执行您的 else 子句if
。那是一个不同的故事。
我能想出的最简洁的方法并不完全漂亮,但也不是很长:
(if (loop []
(cond (or (and (realized? future1) @future1)
(and (realized? future2) @future2)) true
(and (realized? future1) (realized? future2)
(not @future1) (not @future2)) false
:else (recur)))
...)
现在,这用于loop
重复循环,直到发生以下两种情况之一:期货中的任何一种都已实现true
,在这种情况下,循环返回true
; 或所有期货都已实现并且所有期货false
,在这种情况下,循环以false
. (not ...)
将表达式放在其父表达式的末尾很重要(and ...)
,这样您就不会卡在检查是否有任何未来true
或false
直到它们全部实现。
这个新的解决方案可以概括为:
(defmacro future-or [& futures]
`(loop []
(cond (or ~@(for [f futures]
`(and (realized? ~f)
(deref ~f)))) true
(and ~@(for [f futures]
`(realized? ~f))
~@(for [f futures]
`(not (deref ~f)))) false
:else (recur))))
并以与上例相同的方式使用future-or
。
现在,我对优化几乎一无所知。但据我所知,这肯定没有理论上的效率,因为一旦实现了任何给定的未来,就没有必要多次测试它的价值。好吧,这里有两个解决方案,我将其命名为future-some
. 由于被测试的期货必须在每次循环迭代后动态变化,我不得不将它变成一个函数。这样,这种新方法类似于some
,而不是or
。some
在实物上,我改变了行为以获取期货的集合(而不是可变数量的单个参数 -和之间的另一个区别or
)。一种解决方案不进行双重检查(我认为):
(defn future-some [futures]
(if (empty? futures)
false
(let [res (reduce (fn [unrealized f]
(if (realized? f)
(if @f
(reduced true)
unrealized)
(cons f unrealized)))
()
futures)]
(if (true? res)
true
(recur res)))))
这里有很多细节,但要点是:如果没有要测试的期货,则返回false
,否则,它会向下迭代期货列表,测试它们是否已实现。如果实现了未来,并且还取消了对 的引用true
,则迭代中断并返回true
。如果实现了未来但没有取消对 的引用true
,则迭代继续到下一项。如果未来未实现,则添加一个列表以用于 的下一次递归future-some
。
另一个解决方案更简洁,但不太理想:
(defn future-some [futures]
(if (empty? futures)
false
(let [realized (filter realized? futures)]
(if (some deref realized)
true
(recur (remove (set realized) futures))))))
与另一个类似,除了它首先过滤掉已实现,然后测试,然后再次过滤(这次是反向 - 以获得未实现的),如果它需要重复。这第二次过滤是低效的步骤。
我提出的所有解决方案的一个问题是,未来的取消会在取消引用时导致错误,而他们可能应该简单地继续下去,就好像未来是错误的一样。这可以通过在任何取消引用之前将(not (future-cancelled? ...))
表达式放在每个表达式中来解决。(and ...)
或者,对于future-some
函数,您必须将realized?
谓词替换为(some-fn (comp not future-cancelled?) realized?)
, 或#(and (not (future-cancelled %)) (realized? %))
用于胆小的人。
再次,说真的,谢谢你的问题。