Macros 函数/宏仅在参数从上次调用更改时执行函数体

Macros 函数/宏仅在参数从上次调用更改时执行函数体,macros,clojure,functional-programming,clojurescript,Macros,Clojure,Functional Programming,Clojurescript,这应该类似于记忆,但非常不同。虽然memoize应该与纯函数一起使用,但它通常有助于加速与IO相关的函数 我正在寻找的函数/宏的行为应该类似于高阶函数。它产生的功能应: 第一次调用时,它应该调用原始函数,并向其传递参数 记住:参数,返回值 第二次呼叫时 使用相同的参数:它应该返回已记忆的返回值 使用不同的参数:忘记最后一个参数和返回值,调用原始函数,记住当前参数和返回值 第n次调用时,始终将参数与上次调用进行比较,并按照上述方式进行操作 修改memoize的源代码就很容易做到这一点 (de

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

我正在寻找的函数/宏的行为应该类似于高阶函数。它产生的功能应:

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

    • 修改
      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))
      


      这是一个仅使用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
      

      这与memoize完全相同,只是它只记住一个参数->值对.nice,特别是当值已经被heldI意识到我需要一些完全不同的东西(自定义缓存策略)时,避免交换,但基本上我在实现之前就使用了它。附加问题:比较类型化数组的快速、高效内存的方法:)(是的,这些是我的参数,我重复使用它们以提高性能)。@skrat我建议将附加问题作为一个新问题,详细说明如何使用数组。如果您正在重用相同的阵列,那么答案很简单。
      (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