7

clojureで次のことを行うと

(defn sub1a [a]
  (cond
    (= a 0) 0
    true (sub1b (- a 1) )))

(defn sub1b [a]
  (cond
    (= a 0) 0
    true (sub1a (- a 1) )))

(println (sub1a 10))

次のエラーが発生します。

java.lang.Exception: Unable to resolve symbol: sub1b in this context

しかし、私が次のことをした場合:

(defn sub1a [a]
  (cond
    (= a 0) 0
    true (- a 1)))

(defn sub1b [a]
  (cond
    (= a 0) 0
    true (- a 1)))

(defn sub1a [a]
  (cond
    (= a 0) 0
    true (sub1b (- a 1) )))

(defn sub1b [a]
  (cond
    (= a 0) 0
    true (sub1a (- a 1) )))

(println (sub1a 10))

それはうまく動作します。

これは設計によるものですか、それともClojureリーダーの動作方法の機能ですか?

4

2 に答える 2

17

できるよ

(declare sub1a sub1b)

'declare'は、前方宣言を行うためのバインディングのない変数を作成することを特に意味します。

あなたが名前を宣言したもの:

(defn sub1a [a]
  (cond
    (= a 0) 0
    true (sub1b (- a 1) )))

(defn sub1b [a]
  (cond
    (= a 0) 0
    true (sub1a (- a 1) )))

(println (sub1a 10))

また、cond(clojureの場合)でデフォルト条件を指定するための理想的な方法は、:else句を使用することです。これは、T(True)を使用するCommonLispとは少し異なります。したがって、以前のコードは次のように書き直すことができます。

(defn sub1a [a]
  (cond
    (= a 0) 0
    :else (sub1b (- a 1) )))

...
于 2010-08-08T10:53:11.997 に答える
3

正しい解決策は、rkrishnanによって投稿されたとおりです。

質問のこの部分について:

これは設計によるものですか、それともClojureリーダーの動作方法の機能ですか?

実際、これはClojureリーダーとは関係ありません。コンパイラーがシンボルに遭遇するとすぐにVarsに解決するためです(ローカルに名前を付ける場所ではなく、Varに解決するために「最終的に」必要となる位置で) 、もちろん、引用符で囲まれるか、特別なフォームまたはマクロに渡されます)。これは効率の理由から理にかなっています。コンパイル時にシンボルがどのVarを参照するかを知ることで、実行時にシンボルを解決する必要のないコードを生成できます(通常は、Varのを検索する必要がありますが、Var自体は検索する必要はありません)。 )。本当に必要な場合は、実行時にコードでシンボルを解決することができます。

(defn sub1a [a]
  (cond
    (= a 0) 0
    :else ((resolve 'sub1b) (- a 1) )))

(defn sub1b [a]
  (cond
    (= a 0) 0
    :else ((resolve 'sub1a) (- a 1) )))

(println (sub1a 10))

; prints 0 and returns nil

ただし、これはパフォーマンスの特定の低下を引き起こしますが、実際のコードではほとんど正当化されないため、Clojureを使用すると、これが本当に必要なものであると本当に考えている場合は、明示的になります。

于 2010-08-08T18:40:45.980 に答える