【问题标题】:Function/macro to execute function body only when arguments changed from last call仅当参数从上次调用更改时才执行函数体的函数/宏
【发布时间】:2014-06-19 15:19:21
【问题描述】:

这应该类似于memoize,但非常不同。虽然 memoize 应该与纯函数一起使用,但它通常对加速 IO 相关函数很有用。

我正在寻找的函数/宏应该表现得像高阶函数。它产生的功能应该:

  • 第一次调用时,它应该调用原始函数,并将参数传递给它
  • 记住:参数,返回值
  • 第二次调用时
    • 使用相同的参数:它应该返回记忆的返回值
    • 使用不同的参数:忘记最后一个参数和返回值,调用原始函数,记住当前参数和返回值
  • 第 n 次调用时,始终将参数与上次调用进行比较,并按照上述方式进行操作。

【问题讨论】:

  • 这和 memoize 完全一样,只是它只记住一个参数->值对。

标签: macros clojure functional-programming clojurescript


【解决方案1】:

修改memoize 的源代码很容易做到这一点。

(defn memo-one [f]
  (let [mem (atom {})]
    (fn [& args]
      (if-let [e (find @mem args)]
        (val e)
        (let [ret (apply f args)]
          (reset! mem {args ret})
          ret)))))

(defn foo [x] (println "called foo") x)
(def memo-foo (memo-one foo))

但是,已经有一个灵活的记忆库可以做到这一点。

(require '[clojure.core.memoize :as memo])

(defn foo [x] (println "called foo") x)
(def memo-foo (memo/lru foo :lru/threshold 1))

(memo-foo 1)
; called foo
; 1
(memo-foo 1)
; 1
(memo-foo 2)
; called foo
; 2  
(memo-foo 1)
; called foo
; 1

【讨论】:

  • 很好,特别是在值已被持有的情况下避免交换
  • 我意识到我需要一些完全不同的东西(自定义缓存策略),但基本上我在实现之前就使用了它。额外的问题:比较类型化数组的快速、内存有效的方法 :)(是的,这些是我的论点,我将它们重用于性能)。
  • @skrat 我建议将您的奖励问题作为一个新问题提出,并详细说明您如何使用阵列。如果您要重用相同的数组,那么答案很简单。
【解决方案2】:

这是一个仅使用 clojure.core 的版本。我从 A. Webb 的示例中借用了foo 函数进行演示。

(defn memoize-1
  [f]
  (let [previous (atom nil)]
    (fn [& args]
      (second
       (swap! previous
              (fn [[prev-args prev-val :as prev]]
                (if (and prev (= prev-args args))
                  prev
                  [args (apply f args)])))))))


user> (defn foo [x] (println "called foo") x)
#'user/foo
user> (def memo-foo (memoize-1 foo))
#'user/memo-foo
user> (memo-foo 1)
called foo
1
user> (memo-foo 1)
1
user> (memo-foo 2)
called foo
2
user> (memo-foo 1)
called foo
1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-29
    • 2019-03-07
    • 1970-01-01
    相关资源
    最近更新 更多