web-dev-qa-db-ja.com

引数のない関数のClojure defとdefn

Clojureでプログラムを作成しましたが、一部の関数には引数がありません。このような関数を引数なしの「defn」ではなく「def」としてコーディングする利点は何でしょうか?

48
Yazz.com

defsは1回だけ評価されますが、defns(引数ありまたはなし)は、呼び出されるたびに評価(実行)されます。したがって、関数が常に同じ値を返す場合、それらをdefsに変更できますが、それ以外の場合は変更できません。

75
Abhinav Sarkar
user=> (def t0 (System/currentTimeMillis))
user=> (defn t1 [] (System/currentTimeMillis))
user=> (t1)
1318408717941
user=> t0
1318408644243
user=> t0
1318408644243
user=> (t1)
1318408719361
111
jamesqiu

(defn name ...)は、とにかく(def name(fn ...)に変わるマクロです。パラメーターの数は関係ありません。したがって、これは単なるショートカットです。詳細は(doc defn)を参照してください。

39
Roman Bataev

def特殊フォームは、最初の引数として指定された記号で識別されるVarオブジェクトを作成します。識別は、名前空間と呼ばれるマップ内の指定されたシンボルをVarに関連付けることによって作成されます。

Varはある値への参照を保持します(これは(他の中でも)表現できます)。

  • 常にそれ自体の値に評価される定数形式として
    (def x 1) x ; => 1 ; x holds a reference to a number 1

  • 最初はがその結果の値に評価される関数形式として:
    (def x (+ 2 2)) x ; => 4 ; x holds a reference to a number 4

  • Javaメソッド形式、最初はがその結果の値に評価される:)
    (def x (System/currentTimeMillis)) x ; => 1417811438904 ; x holds a reference to a number 1417811438904 x ; => 1417811438904 ; still the same number!

  • ラムダ形式(無名関数)として、最初は関数オブジェクトとして評価されます:
    (def x (fn [] (System/currentTimeMillis))) x ; => #<user$x user$x@4c2b1826> (x) ; function form, function evaluated ; => 1417811438904 (x) ; function form, function evaluated ; => 1417812565866

上記のすべてに簡単なルールがあります。 def特殊形式の場合、2番目の引数として指定されたS式は再帰的に評価されますバインディングが作成される前なので、結果のVarはこの評価の結果にバインドされます。

fnも以前に評価されますが、その結果の値はコードを保持する関数オブジェクトです。このコードは、関数が呼び出されるたびに実行(および評価)されます。そのため、結果は異なります。

defnマクロはdefに似ていますが、内部的には無名関数を作成し、それにVarオブジェクトをバインドします。 2番目の引数はこの関数の本体になり、「通常の」方法では評価されません。評価されたと言うこともできますが、ラムダ形式–評価の結果は関数オブジェクトであり、いくつかの即時計算の結果ではありません。

だから書く:
(defn fun [] 1)

同義語:
(def fun (fn [] 1))

11
siefca