6

とを使用して作成した閉路グラフがdosyncありref-setます。これを渡すと、予想どおりにがprintln得られます。これjava.lang.StackOverflowErrorは、無限にネストされた構造を効果的に印刷しようとしているためです。

私がそうすると、構造を横断してすべてを印刷しようとしない(str my-ref)ように見えるものが作成されることがわかりました。これにより、当面の問題は解決されますが、自分が何に注意を払っている場合にのみ役立ちます。 vertex@23f7d873m画面に印刷します。ある種のカスタムテキスト(おそらくを含む)として、そして他の非参照のものを通常どおり(println my-graph)に印刷するように呼び出すことができるようにしたいと思います。refstr

現在、構造体の各要素を独自に印刷し、の印刷を完全にスキップするカスタム印刷関数がありrefます。(見ることvertex@23f7d873は実際にはあまり有用ではないことがわかります)。これは使いにくく、REPLでのカジュアルな検査の妨げになります。また、swank.core/breakデバッグ中にEmacsの検査官が検査を行うのを妨げます。

1つの詳細は、実際には、私が通常印刷しようとしている他のいくつかのものも含むrefaの値です。defstruct

だから私はどの道を進むべきか疑問に思っています。私はこれらのオプションを見ます:

  1. プロトコルを理解して私のed構造にextend-type適用し、遭遇したときに正しく機能するようにします。これには、構造体のフィールドごとの検査と、構造体に関しては特別な場合が必要ですが、少なくとも、構造体を含むものではなく、構造体に問題を特定します。CharSequencedefstructrefref
  2. CharSequenceに遭遇したときにプロトコルをオーバーライドする方法を理解しますref。これにより、さらにローカライズされた動作が可能になり、構造体の内部にない場合でも、REPLで循環参照を表示できます。これは私の好みのオプションです。
  3. toString私がするとき、あるレベルで呼ばれると私が信じる何かをする方法を理解してくださいprintln。私はこのオプションについて最も無知です。他のものについてもかなり無知ですが、私は読んJoy of Clojureでいて、今はすべて刺激を受けています。

同様に、この解決策は、循環参照を印刷しようとするときに通常はバーフする他のすべてのものに適用する必要がprintあります。pprintどのような戦略を採用する必要がありますか?

ご入力いただきありがとうございます。

4

3 に答える 3

4

私は自分の解決策を見つけました.clojure.core/print-method特定の型ごとにオーバーロードするマルチメソッドを作成し、マルチメソッド内からジェネリック関数を呼び出すだけです. この場合、各マルチメソッドは、print-graph-element参照を処理する方法を知っているジェネリックを呼び出します (参照されたオブジェクトの値を出力しようとするのではなく、参照されたオブジェクトのハッシュを出力するだけです)。この場合、print-method のディスパッチ関数は(type <thing>)、型に応じてディスパッチされると仮定しています。それが、マルチメソッドを書いている方法です。print-method ディスパッチがどのように機能するかを示すドキュメントは実際には見つかりませんでしたが、確かにそのように動作するようです。

このソリューションにより、オブジェクトの名前を入力するだけで済みますv0(repl で (make-vertex) によって作成され、repl によって print-method が呼び出されるなど)、StackOverflow エラーを防ぐことができます。

(defmethod clojure.core/print-method vertex [v writer]
  (print-graph-element v))
(defmethod clojure.core/print-method edge [e writer]
  (print-graph-element e))
于 2012-04-14T10:42:58.640 に答える
4

やりたいことは、新しい名前空間を作成し、clojure がオブジェクトを印刷する方法をモデル化し、clojure のメソッドをデフォルトにする独自の印刷関数を定義することです。

詳細に:

    pr-str と print-method を除いた ns を作成します。マルチメソッドの print-method を作成する (clojure.core にあるものを正確にコピーする) 単に clojure.core/print-method に委譲するデフォルトのメソッドを作成する すべてを再帰的に出力しない clojure.lang.Ref のメソッドを作成する

おまけとして、clojure 1.4.0 を使用している場合は、タグ付きリテラルを使用して、出力を読み取ることもできます。*data-readers*カスタム タグと ref オブジェクトを返す関数のマップをオーバーライドする必要があります。また、バインディングが確実に呼び出されるように、読み取り文字列の動作をオーバーライドする必要があります*data-readers*

java.io.File の例を提供しました

 (ns my.print
   (:refer-clojure :exclude [pr-str read-string print-method]))

 (defmulti print-method (fn [x writer]
         (class x)))

 (defmethod print-method :default [o ^java.io.Writer w]
       (clojure.core/print-method o w))

 (defmethod print-method java.io.File [o ^java.io.Writer w]
       (.write w "#myprint/file \"")
       (.write w (str o))
       (.write w "\""))

 (defn pr-str [obj]
   (let [s (java.io.StringWriter.)]
     (print-method obj s)
     (str s)))

 (defonce reader-map
   (ref {'myprint/file (fn [arg]
               (java.io.File. arg))}))

 (defmacro defdata-reader [sym args & body]
   `(dosync
     (alter reader-map assoc '~sym (fn ~args ~@body))))

 (defn read-string [s]
   (binding [*data-readers* @reader-map]
     (clojure.core/read-string s)))

今、あなたはそのように呼び出すことができます(println (my.print/pr-str circular-data-structure))

于 2012-04-04T14:29:56.827 に答える
1

ループを使用してデータ構造を印刷できるようにするだけの場合は*print-level*、プリンターが下降する深さを制限するように設定してみてください。

user=> (def a (atom nil))
#'user/a
user=> (set! *print-level* 3)
3
user=> (reset! a a)
#<Atom@f9104a: #<Atom@f9104a: #<Atom@f9104a: #>>>

*print-length*無限の長さのデータを処理するときに役立つvarもあります。

于 2012-04-14T15:31:55.447 に答える