先日、Clojure でのクロージャの例を考え出そうとしていました。私は以前に見た例を思いつき、それが適切だと思いました。
残念ながら、それは良いものではなく、何かを提供する必要があると言われました。
誰でも光を当てることができますか?
(defn pow [x n] (apply * (repeat x n)))
(defn sq [y] (pow y 2))
(defn qb [y] (pow y 3))
先日、Clojure でのクロージャの例を考え出そうとしていました。私は以前に見た例を思いつき、それが適切だと思いました。
残念ながら、それは良いものではなく、何かを提供する必要があると言われました。
誰でも光を当てることができますか?
(defn pow [x n] (apply * (repeat x n)))
(defn sq [y] (pow y 2))
(defn qb [y] (pow y 3))
クロージャーは、それ自体のスコープ外の名前付きの値/変数にアクセスできる関数であるため、関数が作成されたときに関数を囲むより高いスコープからアクセスできます (関数の引数と関数内で作成されたローカルの名前付き値は除外されます)。すべての関数が独自のスコープから名前付きの値を使用するだけなので、あなたの例は適格ではありません。
例:
(def foo
(let [counter (atom 0)]
(fn [] (do (swap! counter inc) @counter))))
(foo) ;;=> 1
(foo) ;;=> 2
(foo) ;;=> 3, etc
Nowfoo
は、スコープ外にあるアトムの値を返す関数です。foo
関数はまだそのアトムへの参照を保持しているため、アトムは必要な限りガベージ コレクションされません。
関数を返す関数、つまり高階関数はクロージャの良い例です。
(defn pow [n]
(fn [x] (apply * (repeat n x))))
(def sq (pow 2))
(def qb (pow 3))
閉鎖の別の例。同じ環境を共有する 2 つの関数があります ( state
)。
(defn create-object [init-state]
(let [state (atom init-state)]
{:getter (fn []
@state)
:setter (fn [new-val]
(reset! state new-val))}))
(defn test-it []
(let [{:keys [setter getter]} (create-object :init-value)]
(println (getter))
(setter :new-value)
(println (getter))))
(test-it)
=> :init-value
:new-value