私は Clojure に比較的慣れておらず、 Seven Languages in Seven Weeksの Clojure の章を読んでいますが、本のこのコードが機能しない理由がわかりません。Leiningen と Clojure バージョン 1.5.1 を使用しています。注意深くチェックした後にわかる限り、本に書かれているとおりにコードを正確に入力しました。
コードは次のとおりです。
(ns seven-languages.compass)
(defprotocol Compass
(direction [c])
(left [c])
(right [c]))
(def directions [:north :east :south :west])
(defn turn [base amount]
(rem (+ base amount) (count directions)))
(defrecord SimpleCompass [bearing]
Compass
(direction [_] (directions bearing))
(left [_] (SimpleCompass. (turn bearing 3)))
(right [_] (SimpleCompass. (turn bearing 1)))
Object
(toString [this] (str "[" (direction this) "]")))
ディレクトリ ~/clojure/seven-languages (~/clojure で「lein new Seven-languages」を実行して作成) 内から「lein repl」を実行しています。このディレクトリに対して、私の .clj ファイルは src/seven_languages にあります。これまでのところ、入力してreplから正常にインポートして使用することができました(use 'seven-languages.filenamehere)
。
上記のコードを src/seven_languages/compass.clj として保存した後、これを REPL から実行します。
user=> (use 'seven-languages.compass)
nil
しかし、SimpleCompass の「インスタンス」を定義しようとすると、本とまったく同じように入力すると、次のようになります。
user=> (def c (SimpleCompass. 0))
CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: SimpleCompass, compiling:(NO_SOURCE_PATH:1:8)
を使用してファイルのロードも試み(load-file "src/seven_languages/compass.clj")
ましたが、同じ結果が得られました。実際の読み込みは期待どおりに機能しているように見えたので、 7 週間で 7 つの言語が書かれた以降のバージョンの Clojure では、defprotocol または defrecord の動作に何らかの変更があったのではないかと思います。Clojure の章の導入部で、著者は次のように書いています。
このコードが正しく動作しない理由を誰か教えてください。バージョンの問題である場合、Clojure 1.5.1 用にこのコードをどのように更新しますか?
編集:ああ!これを見つけた後、私はそれを理解しました:
Clojure - deftypeは無視されました - テストでクラス名を解決できません
名前空間の問題です。これは、7LI7W が作成されたバージョン 1.2 からの変更であると推測しています。何らかの理由で、インポートされたファイルの関数は「自動的に処理」されるため、直接使用できますが、型は自動的に処理されません。タイプへのフル パスを含める必要があり、ハイフンではなくアンダースコアを含む実際のパスを使用していることを確認してください。SimpleCompass
フルパスに置き換えることで、コードが機能するようになりましたseven_languages.compass.SimpleCompass
。
user=> (def c (seven_languages.compass.SimpleCompass. 0))
#'user/c
user=> c
#seven_languages.compass.SimpleCompass{:bearing 0}
user=> (left c)
#seven_languages.compass.SimpleCompass{:bearing 3}
user=> (right c)
#seven_languages.compass.SimpleCompass{:bearing 1}