2017-10-12 8 views
2

私はこの本でプログラミングすることを勉強しようとしていますClojure for the Brave and True(CFTBAT)です。クラッシュコースの終わりに、著者はClojureでループを説明するための小さなプログラムを作成します。プログラムのループと再帰の部分を説明するために、著者はloopを使用して小さな例を書いてから、loopを通常の関数定義に置き換えることができます。ClojureとClojureによる再帰と勇気のための

この正常な関数定義の例はわかりません。ここでは、コードは次のとおりです。機能recursive-printerの引数がどこにあるか私が見ることができないので

(defn recursive-printer 
    ([] 
     (recursive-printer 0)) 
    ([iteration] 
     (println iteration) 
     (if (> iteration 3) 
      (println "Bye!") 
      (recursive-printer (inc iteration))))) 

(recursive-printer) 

私は、コードを理解していません。 Clojureでは、関数の引数はカッコで囲まれ、カッコはカッコで囲まれています。したがって、この例では、引数は空の引数[]iterationになります。しかし、なぜそれらもかっこの間に置かれますか?

とは何ですか(recursive-printer 0)関数呼び出しでは、関数自体が呼び出されますか?

誰かがこのコードの仕組みを私に説明できれば、それは非常に感謝しています。

+4

2つの異なる引数リストがあります。 1つの '[]' - 引数なしで呼び出された場合を処理するコードと、1つの引数を指定して呼び出されたときに処理する1つの '[iteration]'です。 –

+2

ところで、この本はオンラインで入手可能なので、リンクが傷ついていない可能性があります。ウェブ版はページごとに指向していないので、「63ページ」はそれを大いに利用している人を助けません。 –

+5

「Arity Overloading」の第3章を参照してください。 –

答えて

2

clojureでは、異なる数の 引数を取ることができるように関数を定義することができます。

(defn foo [] 
    ....) 

は、引数をとらない関数です。このように呼び出されます。

(foo) 

(defn foo [x] 
    ...) 

は1つの引数をとる関数です。それは

(foo :a) 

のように呼び出すことができますが、時には、あなたはゼロまたは1 引数を取る関数を定義することもできます。これを行うには、一般的なイディオムが 機能の主要部分として、再帰関数の定義 にゼロ引数のフォームを使用し、シングル「アキュムレータ」引数のフォームを含めることです

(defn foo 
    ([] ;no argument form 
    ...) 
    ([x] ;single argument form 
    ...)) 

わずかに異なるフォーマットを使用します。あなたは(再帰的なプリンタ)を呼び出すときに、あなたの例を見て、あなたが

(defn recursive-printer 
    ([] ; zero argument form 
     (recursive-printer 0)) 
    ([iteration] ; 1 argument form 
     (println iteration) 
     (if (> iteration 3) 
      (println "Bye!") 
      (recursive-printer (inc iteration))))) 

(recursive-printer) 

を持っていることは、最初の形式(ゼロ引数 形式)を呼び出します。この形式では、1つの引数が0の関数が呼び出されます。この は、2番目の形式を呼び出します。

'else'文を実行すると、2番目の形式では最初に引数が出力され、 が3より大きいかどうかがテストされます。最初の呼び出しでは0ではないためです。現在の引数が の新しい引数を持つ再帰呼び出しが1増加します。引数が1で、 が出力されます。テストは1が> 3でないためにまだfalseであるので、関数は を引数1(すなわち2)だけ増やして再び呼び出されます。この呼び出しでは2が出力され、テストは がまだ3を超えていないので関数は引数 を3に増加して再び呼び出されます。この呼び出しでは、3が出力され、テストはまだ> 3ではないため、 引数は4にインクリメントされ、関数は 引数として4で再度呼び出されます。値4が出力されますが、今回の4は3より大きいので、 "Bye"という文字列は と印刷されます。これが終了条件であるため、それ以上の再帰呼び出しは行われません。 はスタックを巻き戻し、関数は終了します。

1

我々はゼロアリティドロップすることができます。

(defn recursive-printer [iteration] 
    (println iteration) 
    (if (> iteration 3) 
    (println "Bye!") 
    (recursive-printer (inc iteration)))) 

を...と明示的0引数で関数を呼び出す:

(recursive-printer 0) 
0 
1 
2 
3 
4 
Bye! 
=> nil 

これは、私たちは再帰に集中することができます。再帰呼び出しは、(尾の位置に)行って最後のものであるので、我々は代わりにrecurを使用することができます。

(defn recursive-printer [iteration] 
    (println iteration) 
    (if (> iteration 3) 
    (println "Bye!") 
    (recur (inc iteration)))) 

を...まったく同じ効果が。

余分なアリティは物事を混乱させるだけだと思います。

+0

著者は、 'loop'や' recur'を使わずに再帰の例を見せたいと思っています。 – guillaume8375

関連する問題