2015-10-15 2 views
8

Clojureでは、定義の前に関数を呼び出すと、Clojure:なぜ、関数がソースコードの定義の前に呼び出された場合に `declare`でなければならないのですか?

(foo (bar 'a)) 

(defn bar [] ...) 

コンパイルされていません。追加する必要があります

(declare bar) 

(foo (bar 'a))より前に入力してください。なぜClojureはこのように設計されていますか?つまり、Java、Python、PHP、Scala、Haskell、その他のリスプ、特にダイナミック型言語のC/C++以外のほとんどの言語では、関数宣言は必要ありません。コールの前または後。私はそれを使用するのが不快であると感じています。

答えて

13

Clojureのは、シングルパスのコンパイル(だけでなく、私は単純化するには、次のリンクを読んで)行います

をだから、あなただけのソースを読めばという論理的と思われます一度、上から下に進む宣言のようなものはありません安全にそれを行う。リッチ(最初のリンク)を引用する

しかし、コンパイラは前 バーを見たことがなかったときに、何が、ここで起こるのでしょうか?

`(defn foo [] (bar))` 

やCLで:

`(defun foo() (bar))` 

CLは喜んでそれをコンパイルし、バーが定義されることはありません場合は、ランタイムエラーが発生します。さて、コンパイル中に (シンボル)がバーに使用されましたか?フォームが読まれたときにそれを拘束した記号 。だから、実行時に エラーが発生し、バーが他のパッケージで定義されていることに気付いた場合は、 インポートを忘れてしまいます。他のパッケージとBAMをインポートしようとしました。別のエラー - 競合、他のパッケージ:バーがread-in-package:barと競合しています。その後、 あなたは無神論について学びます。

Clojureでは、フォームがコンパイルされず、 というメッセージが表示され、barにはvarが保持されません。 other-namespaceが必要であり、続行してください。

私は非常にこの経験を好むので、 はこれらのトレードオフを行いました。 非インターナショナル・リーダーを使用し、定義/宣言のみでインターナショナルを使用することにより、他の多くの利点が生まれました。 循環参照をサポートするために、私はそれらをあきらめたり、先に述べた便益、つまり を寄付するつもりはありません。

+1

Rich Hickeyの説明でこれらの古いHN投稿を掘り出した方が優れています。私は長い間彼らを再び見つけようとしていました。 –

+2

これは、一貫した方法で、つまり下から上にコードを強制的に読み込むことを意味します。関数を見ると、その内部のすべての宣言が名前空間内で宣言されていることがわかります。ちょっとしたことですが、コードを読むときには便利です。 – shmish111

関連する問題