4

我正在关注“Clojure in Action”,对此我感到困惑:

(defn with-log [function-to-call log-statement ]
      (fn [& args]
          (println log-statement)
          (apply  function-to-call args)))

这是让我感到困惑的代码段。到目前为止,这是我能破译的:

(defn with-log [function-to-call log-statement ] ..) 定义了一个名为“with-log”的函数,它接受参数“function-to-call”和“log-statement”以及function-to- call 是作为参数传递给此函数的函数。下一部分让我感到困惑:(fn [& args] .... 这里定义了一个匿名函数吗?'with-log' 函数是否返回一个新的函数定义?

(fn [& args]
          (println log-statement)
          (apply  function-to-call args))

因此,通过调用 (with-log somefunc "my label") - 它只是返回一个新的匿名函数吗?还是调用匿名函数?

4

3 回答 3

6

with-log将产生一个函数,当调用该函数时,它将完全执行所做的操作,除了将打印到之前使用给匿名函数的参数进行评估function-to-call的副作用。log-statement*out*function-to-call

这是装饰器模式的一个示例——通过将现有函数包装在另一个函数中来扩展现有函数的行为,即with-log使用(fn ...)表单创建的匿名函数。

为了使装饰器函数with-log与任何可以想象function-to-call的 . 一起工作,指定匿名函数的参数列表,以便可以使用(fn [& args] ...). 当匿名函数调用function-to-call它时,用函数“解包”参数列表apply)。

使用方法with-log可能是:

((with-log some-fn "Calling some-fn") arg1 arg2)

或者

(defn my-fn [a b]
  (+ a b))
(def my-fn-with-logging (with-log my-fn "Calling my-fn"))

(my-fn 1 2) ; evaluates to 3
(my-fn-with-logging 1 2) ; prints "Calling my-fn" and evaluates to 3 
于 2012-07-29T20:04:36.060 回答
1

它正在返回匿名函数,并且没有被调用。

例如,这将使用给定的参数调用匿名函数:

((with-log some-fn "log statement") arg1 arg2)

这是有效的,因为返回的函数是列表中的第一项,这意味着它像任何其他函数一样被调用。

于 2012-07-27T20:04:25.103 回答
0

你是对的。(fn ..)是一种创建匿名函数的形式。这段代码,给定一个函数f和一些值s,将返回一个函数,当调用该函数时,将打印s然后调用f

user=> (defn with-log [function-to-call log-statement ]
      (fn [& args]
          (println log-statement)
          (apply  function-to-call args)))
#'user/with-log
user=> (with-log + "String")
#<user$with_log$fn__1 user$with_log$fn__1@147264b1>
user=> ((with-log + "String") 1 2 3)
String
6
user=>

注意以 开头的行#<user$...。这是刚刚创建的匿名函数的内部标识符,即简单调用with-log返回一个函数。然后我们将相同的函数(就其行为而言是相同的;实际上它将是不同的对象,因为每次调用with-log都会创建相同函数的新“实例”)应用于多个参数。"String"字符串被打印出来,然后 REPL 向我们显示(+ 1 2 3).

在这里您可以了解更多信息。

于 2012-07-27T20:04:53.840 回答