如何覆盖引用类型的println行为

Son*_*oth 5 graph clojure cyclic charsequence pprint

我有一个使用dosync和创建的循环图ref-set.当我传递给println我时,我得到了一个java.lang.StackOverflowError我所期望的,因为它有效地试图打印一个无限嵌套的结构.

我发现,如果我这样做(str my-ref)会产生看起来像vertex@23f7d873并且实际上并不试图遍历结构并将所有东西都打印出来的东西,所以这就解决了这个问题,但是只有在我非常小心我的情况时才会有所帮助. m打印到屏幕上.我希望能够打电话给(println my-graph)它打印ref作为某种类型的自定义文本(可能涉及str),以及其他非ref的东西通常.

目前我有一个自定义打印功能,可以自己打印结构的每个元素,并完全跳过打印ref.(事实证明,看着vertex@23f7d873实际上并不是非常有用).使用起来很尴尬,阻碍了在REPL中对东西进行随意检查,同时也阻止了Emacs检查员在swank.core/break调试时查看内容.

一个细节ref实际上是一个值,defstruct其中还包含一些我试图正常打印的其他东西.

所以我想知道我应该走哪条路.我看到这些选项:

  1. 弄清楚extend-type并将CharSequence协议应用于我的defstructed结构,以便在遇到ref它时可以正常工作.这仍然需要对结构进行逐个字段检查,并且需要特殊情况ref,但至少它将问题本地化为结构而不是包含结构的任何内容.
  2. 弄清楚如何CharSequence在遇到协议时覆盖协议ref.这允许更加本地化的行为,并允许我在REPL处查看循环引用,即使它不在结构体内.这是我的首选.
  3. 弄清楚如何做toString我认为在某种程度上被称为某种程度的事情println.我对这个选项最无知.对其他人一无所知,但我一直在读书Joy of Clojure,现在我受到了启发.

同样,此解决方案应该适用于printpprint尝试打印循环引用时通常会禁用的任何其他内容.我应该采用什么策略?

非常感谢任何输入.

bmi*_*are 4

您想要做的是创建一个新的命名空间并定义您自己的打印函数,该函数模拟 clojure 打印对象的方式,并默认为 clojure 的方法。

详细地:

    创建一个不包括 pr-str 和 print-method 的 ns。创建一个多方法打印方法(准确复制 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)))
Run Code Online (Sandbox Code Playgroud)

现在你可以像这样打电话(println (my.print/pr-str circular-data-structure))