かなり頻繁に、私は交換します!新しい値を計算する際に 1 つ以上の外部値を使用する無名関数を使用するアトム値。これを行うには 2 つの方法があります。1 つはクロージャーであり、もう 1 つはそうではありません。
以下は、変数の数値をアトムに追加する簡単な例です。両方のアプローチを示しています。
(def my-atom (atom 0))
(defn add-val-with-closure [n]
(swap! my-atom
(fn [curr-val]
;; we pull 'n' from outside the scope of the function
;; asking the compiler to do some magic to make this work
(+ curr-val n)) ))
(defn add-val-no-closure [n]
(swap! my-atom
(fn [curr-val val-to-add]
;; we bring 'n' into the scope of the function as the second function parameter
;; so no closure is needed
(+ curr-val val-to-add))
n))
これはでっち上げの例であり、もちろん、この特定の問題を解決するためにこのコードを実際に記述することはありません。理由は次のとおりです。
(swap! my-atom + n)
追加の機能を必要とせずに同じことを行います。
しかし、より複雑なケースでは、関数が必要であり、疑問が生じます。私にとって、この問題を解決する 2 つの方法は、コーディングの観点からはほぼ同じ複雑さです。その場合、どちらを優先する必要がありますか? 私の作業上の仮定は、非クロージャ方式の方が優れているということです (コンパイラが実装するのが簡単だからです)。
この問題を解決する 3 つ目の方法があります。これは、無名関数を使用しないことです。別の名前付き関数を使用する場合、クロージャーを使用することはできず、問題は発生しません。しかし、無名関数をインライン化すると、コードが読みやすくなることがよくあるので、そのパターンをツールキットに残しておきたいと思います。
ありがとう!
以下のA.Webbの回答に応じて編集します(これは長すぎてコメントに入れることができませんでした):
質問での「効率」という言葉の使用は誤解を招くものでした。より良い言葉は「エレガンス」または「シンプルさ」だったかもしれません。
Clojure について私が気に入っている点の 1 つは、他の言語では特定のアルゴリズムをより高速に実行するコードを作成できる一方で、慣用的な Clojure コードを作成すると、かなり高速になり、シンプルでエレガントで保守しやすいことです。 . 解決しようとしている問題が複雑になるにつれて、単純さ、優雅さ、保守性がますます重要になります。IMO、Clojure は、この意味で、複雑な問題の全範囲を解決するための最も「効率的な」ツールです。
私の質問は本当に - この問題を解決する方法が 2 つありますが、より慣用的で Clojure 風の方法は何ですか? 私がその質問をするとき、2 つのアプローチがどれだけ「速い」かが 1 つの考慮事項です。それは最も重要なものではありませんが、これが一般的なパターンであり、さまざまなアプローチが他の観点からの洗い流しである場合、それは正当な考慮事項であると私は思います. 以下の A. Webb の回答は、「おっと! 雑草から引き戻せ! コンパイラはどちらのアプローチも問題なく処理し、ターゲット プラットフォームなどの雑草に深く入り込まない限り、各アプローチの相対的な効率を知ることはできません。 . したがって、言語の名前からヒントを得て、そうするのが理にかなっている場合は、クロージャーを使用してください。"
2014 年 4 月 10 日の最終編集
A. Webb の回答を承認済みとしてマークしますが、A. Webb の回答と omiel の回答は本当に受け入れていますが、残念ながら両方を受け入れることはできません。無償の。
私が Clojure で気に入っている点の 1 つは、Clojure で共同作業を行う人々のコミュニティです。コンピュータ言語を学ぶということは、コードの構文を学ぶということだけではありません。より根本的には、問題について考えて理解するパターンを学ぶということです。Clojure とその背後にある Lisp には、信じられないほど強力な一連のパターンがあります。たとえば、ホモイコニシティ (「データとしてのコード」) は、マクロを使用してコンパイル時にコードを動的に生成できることを意味します。また、分解により、複雑なデータ構造を簡潔かつ読みやすくアンパックできます。どのパターンも Clojure に固有のものではありませんが、Clojure は問題解決を楽しくする方法ですべてをまとめています。そして、それらのパターンを学ぶ唯一の方法は、すでにそれらを知っていて使用している人々から学ぶことです. 1 年以上前に Clojure を初めて選んだとき、私が Scala やその他の候補よりも Clojure を選んだ理由の 1 つは、Clojure コミュニティーが有益で建設的であるという評判だったからです。そして、私はがっかりしたことはありません - 私の質問に関するこのやり取りは、StackOverflow や他の場所の他の多くの人と同じように、コミュニティが私のような初心者を助けようとしている様子を示しています - ありがとう!