Ste*_*gle 13 variables clojure lazy-evaluation
我有一些计算有点昂贵(启动数据库),我只想创建数据库,如果我真的要使用它.我正在寻找一个引用变量(或只是一个普通的变量,如果可能的话),它只会在它被使用(或解除引用)的情况下评估它的值.概念上像以下一样的东西.
(def v (lazy-var (fn [] (do (println "REALLY EXPENSIVE FUNCTION") true))))
Run Code Online (Sandbox Code Playgroud)
而且在将来,当我要么使用var v,或者调用@v时,我会打印出"真正昂贵的功能",并且从那里v的值为true.这里重要的是fn直到变量被引用(de)才被评估.在需要时,该函数仅被评估一次以计算变量的值.在clojure中这可能吗?
Jon*_*ier 29
delay 对于这个应用程序将是完美的:
delay- (delay & body)获取一个表达式体并生成一个Delay对象,该对象仅在第一次强制(使用
force或deref/@)时调用正文,并将缓存结果并在所有后续force调用中返回它.
放置代码以在delay调用体内构造数据库句柄,存储为Var.然后在需要使用DB句柄时取消引用此Var - 在第一个取消引用时将运行正文,并在随后的解引用中返回缓存的句柄.
(def db (delay (println "DB stuff") x))
(select @db ...) ; "DB stuff" printed, x returned
(insert @db ...) ; x returned (cached)
Run Code Online (Sandbox Code Playgroud)
Clojure 1.3为此目的引入了memoize功能:
(记忆f)
返回引用版本的引用透明函数.该函数的memoized版本保留了从参数到结果的映射的缓存,并且当经常重复具有相同参数的调用时,以更高的内存使用为代价具有更高的性能.
在您的示例中,使用memoize替换不存在的lazy-var:
(def v (memoize (fn [] (do (println "REALLY EXPENSIVE FUNCTION") true))))
(v)
=>REALLY EXPENSIVE FUNCTION
=>true
(v)
=>true
Run Code Online (Sandbox Code Playgroud)
(延迟expr)也做了另一个答案解释的工作.关于解除引用延迟的额外注释 - force和deref/@之间的差异是如果在非延迟变量上使用force,则不会抛出异常,而deref/@可能抛出ClassCastException"无法转换为clojure.lang.IDeref".
| 归档时间: |
|
| 查看次数: |
2060 次 |
| 最近记录: |