web-dev-qa-db-ja.com

Clojureでletとif-letを使用する場合

letではなくif-letを使用すると、コードの見栄えが良くなり、パフォーマンスに影響がありますか?

36
Arthur Ulfeldt

コードの「if」部分でthen条件の値を参照する場合は、 if-let を使用する必要があると思います。

つまり、代わりに

(let [result :foo]
  (if result
    (do-something-with result)
    (do-something-else)))

あなたが書く:

(if-let [result :foo]
  (do-something-with result)
  (do-something-else))

これは少しすっきりしていて、さらにレベルをインデントする手間が省けます。効率に関する限り、マクロ展開はそれほどオーバーヘッドを追加しないことがわかります。

(clojure.core/let [temp__4804__auto__ :foo]
  (if temp__4804__auto__
    (clojure.core/let [result temp__4804__auto__]
      (do-something-with result))
    (do-something-else)))

これは、コードの「else」部分でバインディングを参照できないことも示しています。

76
harto

if-letの適切な使用例は、照応を使用する必要をなくすことです。たとえば、Arcプログラミング言語はaifというマクロを提供します。これにより、特定の式が次のように評価されたときに、itフォームの本体内にifという名前の特別な変数をバインドできます。論理的に真。 Clojureでも同じものを作成できます。

(defmacro aif [expr & body]
  `(let [~'it ~expr] (if ~'it (do ~@body))))

(aif 42 (println it))
; 42

これは、照応がネストしないことを除いて、問題なく良好ですが、if-letは次のことを行います。

(aif 42 (aif 38 [it it]))
;=> [38 38]

(aif 42 [it (aif 38 it)])
;=> [42 38]

(if-let [x 42] (if-let [y 38] [x y]))
;=> [42 38]
34
fogus