2

我有这个烦人的问题:

包装器是接受一个函数的函数,并返回另一个接受参数的函数,对参数执行某些操作并将其粘贴回函数中。

(定义包装 [func]
  (fn [参数]
    (func (do-something-to params))))

我想做的是跟踪从包装器到包装器的参数更改

例如,我可以定义两个包装器:

(defn wrap-inc [func]
  (comp func inc))

(defn wrap-double [func]
  (comp func #(* % 2)))

然后,

(def h (-> #(* % 3)
       包装公司
       包裹双))

相当于:

(def h (fn [x] (* (inc (* 2 x)) 3)))
(h 1) => 9

现在,我想定义dbg->这样

(def h-dbg (dbg-> #(* % 3)
                  包装公司
                  包裹双))

仍然给我相同的功能等价物,但也要跟踪旧值和新值:

(h-dbg 1) => 9

但也会在控制台中显示调试信息:

“双包装:(输入:1,输出:2)”
“包装公司:(输入:2,输出 3)”

这种模式对于调试像这样的环包装器以弄清楚每个环在做什么非常有用,例如,这个典型的例子:

(定义开始 []
  (码头/运行码头
   (-> #'路由处理程序
       ;;(包装重新加载修改 ["clj-src"])
       (包装文件“资源/公共”)
       包装文件信息
       换行十进制大小写参数
       换行关键字参数
       包装嵌套参数
       包装参数
       wrap-ignore-trailing-slash) {:port 8890 :join? 错误的}))
4

3 回答 3

2

我相信您正在寻找一种叫做writer monad的东西。

这是对 Writer monad 的一个很好的解释以及它的一些实际操作示例(抱歉,它在 Haskell 中)。

基本上,这个 monad 可以帮助您编写函数,这些函数除了“正常”输出之外还返回一个日志记录值。例如,如果您有以下类型的函数:

f :: a -> (b, l)
g :: b -> (c, l)

您可以使用 writer monad 组合它们以获得具有类型的新函数:

h :: a -> (c, l)

警告:Clojure 宏在组合一元函数->->>不能以完全相同的方式使用,因为您需要bind用于组合。

作为替代解决方案,您可以使用具有副作用的包装器:

(defn wrapper
  [f]
  (fn [& params]
      (print params) ;; or some other logging operation
      (apply f params)))

这是因为函数体中最后一个表达式的值是它的返回值——之前的表达式被求值并且它们的结果被丢弃。

于 2012-09-11T13:18:06.967 回答
0

一种快速而肮脏的方法是将其填充到宏中……此实现仅执行具有单值参数的函数。

(定义换行打印 [f]
  (fn [& 参数]
    (print " ->" (second (re-find #"\$(.*)@" (str f))) args)
    (应用 f args)))

(-> 3 ((wrap-print inc)) ((wrap-print dec)))
;; => "-> inc (3) -> dec (4)"

(defmacro dbg-> [n & funcs]
  (println"")
  (打印 n)
  (让 [wfncs (map #(list (list wrap-print %)) funcs)]
     `(-> ~n ~@wfncs )))

(dbg-> 3 inc dec)
;; =>“3 -> inc (3) -> dec (4)”

于 2012-09-13T00:05:01.477 回答
-1

也许add-watch可以帮助你做到这一点。

限制是您只能观看引用(atom/ref/var/agent)。

于 2012-09-11T00:32:50.020 回答