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 ] ..) は、引数「function-to-call」と「log-statement」と function-to- を取る「with-log」という名前の関数を定義しています。 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 に答える