我有这个唠叨的问题:
Wrappers是接受函数的函数,返回另一个接受参数的函数,对参数执行某些操作并将其重新添加到函数中。
(defn wrapper [func] (fn [params] (func (do-something-to params))))
我想要做的是跟踪从包装器到包装器的参数更改
例如,我可以定义两个包装器:(defn wrap-inc [func] (comp func inc)) (defn wrap-double [func] (comp func #(* % 2)))
然后,
(def h (-> #(* % 3) wrap-inc wrap-double))
相当于:
(def h (fn [x] (* (inc (* 2 x)) 3))) (h 1) => 9
现在,我想要定义dbg->
以便
(def h-dbg (dbg-> #(* % 3) wrap-inc wrap-double))
仍然给我相同的功能等价物,但也跟踪旧的和新的值:
(h-dbg 1) => 9
但也会在控制台中显示调试信息:
"wrap-double: (in: 1, out: 2)" "wrap-inc: (in: 2, out 3)"
这种模式对调试这样的环包装器非常有用,可以弄清楚每个包装器的作用,例如,这个典型的例子:
(defn start [] (jetty/run-jetty (-> #'routes-handler ;;(wrap-reload-modified ["clj-src"]) (wrap-file "resources/public") wrap-file-info wrap-decamelcase-params wrap-keyword-params wrap-nested-params wrap-params wrap-ignore-trailing-slash) {:port 8890 :join? false}))
答案 0 :(得分:2)
我相信你正在寻找一种叫做writer monad的东西。
Here's对作家monad的一个很好的解释以及它在行动中的一些例子(对不起,它在Haskell中)。
基本上,这个monad可以帮助你编写除了“正常”输出之外还返回记录值的函数。例如,如果您有这些类型的函数:
f :: a -> (b, l)
g :: b -> (c, l)
你可以使用编写器monad来组合它们以获得一个类型为的新函数:
h :: a -> (c, l)
警告:在编写monadic函数时,Clojure宏->
和->>
不能以完全相同的方式使用,因为您需要使用{{1}对于构图。
作为替代解决方案,您可以使用副作用包装器:
bind
这是有效的,因为函数体中最后一个表达式的值是它的返回值 - 先前的表达式被计算并且它们的结果被抛弃了。
答案 1 :(得分:0)
快速而肮脏的方法是将其填充到宏中......此实现仅使用单值参数执行函数。
(defn wrap-print [f] (fn [& args] (print " ->" (second (re-find #"\$(.*)@" (str f))) args) (apply f args))) (-> 3 ((wrap-print inc)) ((wrap-print dec))) ;; => "-> inc (3) -> dec (4)" (defmacro dbg-> [n & funcs] (println "") (print n) (let [wfncs (map #(list (list wrap-print %)) funcs)] `(-> ~n ~@wfncs ))) (dbg-> 3 inc dec) ;; => "3 -> inc (3) -> dec (4)"
答案 2 :(得分:-1)
也许add-watch可以帮助您做到这一点。
限制是您只能观看参考(atom / ref / var / agent)。