5

Clojure をいじり始めたばかりで、いくつかの機能を理解するのに役立つ簡単なスクリプトを作成しました。次のように始まります。

(def *exprs-to-test* [  
    "(filter #(< % 3) '(1 2 3 4 3 2 1))"
    "(remove #(< % 3) '(1 2 3 4 3 2 1))"
    "(distinct '(1 2 3 4 3 2 1))"
])

次に、 を通過し*exprs-to-test*、それらすべてを評価して、出力を次のように出力します。

(doseq [exstr *exprs-to-test*]
    (do 
        (println "===" (first (read-string exstr)) "=========================")
        (println "Code: " exstr)
        (println "Eval: " (eval (read-string exstr)))
    )
)

上記のコードはすべて正常に動作しています。ただし、繰り返されるので、次のように繰り返しをなくすため(read-string exstr)に使用しようとしました:let

(doseq [exstr *exprs-to-test*]
    (let [ex (read-string exstr)] (
        (do 
            (println "===" (first ex) "=========================")
            (println "Code: " exstr)
            (println "Eval: " (eval ex))
        )
    ))
)

しかし、これは の最初の項目に対して 1 回機能し*exprs-to-test*、その後NullPointerException. letクラッシュの原因の追加はなぜですか?

4

3 に答える 3

4

他の答えは部屋の中の象を無視していると思います: なぜあなたはこれをしているのですか? あなたのコードには、Clojure の学習を通じて間違った道を歩んでいるのではないかと心配するものがたくさんあります。

  • グローバル バインディングの使用 ( exprs-to-test )
  • doseq/println を使用してコードを順番に試す
  • eval の使用

Clojure の API を学ぶ最良の方法は、REPL を使用することです。Vim、Emacs、または IDE など、テキスト ファイル内の静的コードと対話型 REPL の間を簡単に行き来できるように、環境をセットアップする必要があります。以下は、いくつかの Clojure IDE の適切な内訳です​​。

ここで、コードに関する限り、覚えておくべきことがいくつかあります。まず、eval を使用する正当な理由はほとんどありません。これを行っていることに気付いた場合は、本当に必要かどうかを自問してください。次に、Clojure は関数型言語であり、通常は "do" マクロ セットを使用する必要がないことを思い出してください。「do」マクロは、副作用が必要な場合に役立ちます (この例では、副作用は *out* への println です)。最後に、グローバル変数の使用も避ける必要があります。vars を使用する必要がある場合は、バインディング マクロを使用して vars をスレッドにローカルにバインドし、不変の値にすることを検討してください。これにより、同時実行の問題がなくなります。

Clojure を効果的に活用するためにプログラミングについて考える方法に必要な変化を真に理解するために、Clojure のプログラミングまたは LISP に関する別のより深いリファレンスを取り上げることをお勧めします。ここでのあなたの小さなサンプルは、Clojure で命令型のコードを書こうとしているかのように感じさせますが、これはまったくうまく機能しません。

于 2010-03-17T04:42:37.927 に答える
1

ブライアンはすでにあなたの質問に答えているので、let-formの一般的な指針をいくつか示したいと思います。

于 2010-03-08T08:55:09.790 に答える