自定义地图打印方式:键入Clojure

自定义地图打印方式:键入Clojure,clojure,string-formatting,pretty-print,Clojure,String Formatting,Pretty Print,漂亮的印刷这张地图很难看: {:type :move, :name :boost, :from {:nodeid :plus, :name :left-operand, :value {:args [:result :right-operand], :f #object[fargish.workspace_test$fn__159675$fn__159678 0xb3f518f "fargish.workspace_test$fn

漂亮的印刷这张地图很难看:

  {:type :move,
   :name :boost,
   :from
   {:nodeid :plus,
    :name :left-operand,
    :value
    {:args [:result :right-operand],
     :f
     #object[fargish.workspace_test$fn__159675$fn__159678 0xb3f518f "fargish.workspace_test$fn__159675$fn__159678@b3f518f"]},
    :dockclass :input,
    :ref [:plus :left-operand]},
   :to
   {:nodeid :source11,
    :name :output,
    :value 11,
    :dockclass :output,
    :ref [:source11 :output]},
   :do
   #object[fargish.workspace$do_boost 0x179d226e "fargish.workspace$do_boost@179d226e"],
   :do-hypothetically
   #object[fargish.workspace$do_hypothetical_boost 0x68d6475a "fargish.workspace$do_hypothetical_boost@68d6475a"]}
大多数时候,我不需要看到大部分。我希望它看起来大致像这样:

#boost{:from [:plus :left-operand] :to [:source11 :output]}
Clojure是否提供了一个允许我插入代码的钩子,以便如果映射的
:type
键的值为
:move
str
将调用我编写的函数来生成字符串

我已经调查过了。如果我理解正确的话,这将扩展一个multi方法,它可以分派参数的类型,即。clojure.lang.PersistentArrayMap,而不是映射的
:type
。好了,没有办法“转发”到以前定义的multi方法,否则我可以为clojure.lang.PersistentArrayMap编写一个
打印方法
,查看
:type
,然后调用泛型方法,如果它的值不是
:move

即使只是定制
pprint
也会有所帮助。从理论上讲,
pprint
是非常可定制的,但我还没有发现可以解释这一点。不完整,表明
pprint
未真正完成


影响
pprint
的输出会很好,但严格来说这不是必需的。只要能够影响
str
print
就非常有帮助。

打印方法
:在对象的元数据上键入
键。只需将
:键入
放在元数据中,而不是(或添加到)实际地图本身,您就可以定义自己的打印方法。

有一个漂亮的打印包,您可以使用它,它将非常接近您想要的内容,当您的输出量很大且难以直观理解时,您仍然可以享受到漂亮打印的好处。我在下面给出了一些例子:

; Basic zprint pretty-print of a similar map.  Note that it orders the keys
; alphabetically

user=> (zprint soq)
{:do #<Fn@4d0e1990 clojure.lang.PersistentList/Primordial>,
 :do-hypothetically #<Fn@4d0e1990 clojure.lang.PersistentList/Primordial>,
 :from {:dockclass :input,
        :name :left-operand,
        :nodeid :plus,
        :ref [:plus :left-operand],
        :value {:args [:result :right-operand],
                :f #<Fn@4d0e1990 clojure.lang.PersistentList/Primordial>}},
 :name :boost,
 :to {:dockclass :output,
      :name :output,
      :nodeid :source11,
      :ref [:source11 :output],
      :value 11},
 :type :move}

; You can order the keys so the ones you care about come in the order
; you want.

user=> (zprint soq {:map {:key-order [:name :from :to]}})
{:name :boost,
 :from {:name :left-operand,
        :dockclass :input,
        :nodeid :plus,
        :ref [:plus :left-operand],
        :value {:args [:result :right-operand],
                :f #<Fn@4d0e1990 clojure.lang.PersistentList/Primordial>}},
 :to {:name :output,
      :dockclass :output,
      :nodeid :source11,
      :ref [:source11 :output],
      :value 11},
 :do #<Fn@4d0e1990 clojure.lang.PersistentList/Primordial>,
 :do-hypothetically #<Fn@4d0e1990 clojure.lang.PersistentList/Primordial>,
 :type :move}

; You can get zprint to ignore keys completely

user=> (zprint soq {:map {:key-order [:name :from :to] :key-ignore-silent [[:from :name] :dockclass :nodeid :value :do :do-hypothetically :type [:to :name]]}})
{:name :boost,
 :from {:ref [:plus :left-operand]},
 :to {:ref [:source11 :output]}}

; You can configure zprint to do this all the time

user=> (zprint.core/set-options! {:map {:key-order [:name :from :to] :key-ignore-silent [[:from :name] :dockclass :nodeid :value :do :do-hypothetically :type [:to :name]]}})

; Now you just zprint it...

user=> (zprint soq)
{:name :boost,
 :from {:ref [:plus :left-operand]},
 :to {:ref [:source11 :output]}}
;基本zprint类似地图的漂亮打印。注意,它对键进行了排序
; 按字母顺序
用户=>(zprint soq)
{:做#,
:假设,
:从{:dockclass:input,
:名称:左操作数,
:nodeid:plus,
:ref[:正:左操作数],
:value{:args[:结果:右操作数],
:f#},
:姓名:boost,
:到{:dockclass:输出,
:名称:输出,
:nodeid:source11,
:ref[:source11:输出],
:值11},
:type:move}
; 你可以订购钥匙,这样你关心的钥匙就可以按顺序来了
; 你想要的。
user=>(zprint-soq{:map{:key-order[:name:from:to]})
{:姓名:boost,
:from{:name:左操作数,
:dockclass:输入,
:nodeid:plus,
:ref[:正:左操作数],
:value{:args[:结果:右操作数],
:f#},
:到{:name:output,
:dockclass:输出,
:nodeid:source11,
:ref[:source11:输出],
:值11},
:do#,
:假设,
:type:move}
; 您可以让zprint完全忽略键
user=>(zprint-soq{:map{:key-order[:name:from:to]:key-ignore-silent[:from:name]:dockclass:nodeid:value:do:do假设:type[:to:name]})
{:姓名:boost,
:来自{:ref[:plus:左操作数]},
:到{:ref[:source11:output]}
; 您可以将zprint配置为始终执行此操作
user=>(zprint.core/set-options!{:map{:key-order[:name:from:to]:key-ignore-silent[:from:name]:dockclass:nodeid:value:do:do假设:type[:to:name]})
; 现在你只要把它打印出来。。。
用户=>(zprint soq)
{:姓名:boost,
:来自{:ref[:plus:左操作数]},
:到{:ref[:source11:output]}
您可以使用
~/.zprintrc
文件配置zprint,以便随时执行此操作

您还可以使用czprint对其进行着色,也可以使用:key颜色贴图以任何方式对关键帧进行着色。当我看一系列的地图时,我发现这很有用——改变一个键的颜色并按我想要的方式排列这些键可以让我更容易地理解一系列地图

构建一个函数来查看
:type
,然后调用zprint是很简单的
任何适合该类型的选项。当然,:ref仍然存在,但当您有大量输出时,需要进行权衡,zprint pretty printing开始使用,而且它更易于阅读和理解。

恐怕您只能依靠pprint了。它的使用不如核心印刷设备那么多,我相信正因为如此,它没有那么灵活:很少有人关心扩展它。我认为你能做的最好的事情是:定义一种新的pprint分派方法来代替简单分派,在分派中实现你想要的任何自定义内容,然后将其他决策委托给简单分派。但是它不像打印方法那么简单,因为它不考虑默认的元数据。你应该写下这个答案。OP明确地询问了pprint。哇,它起作用了!很容易,甚至!(@LeonGrapenthin问了我下一个问题。)谢谢。@LeonGrapenthin我会澄清这个问题。我很高兴能够修改print的行为。pprint也很好,但这不是绝对必要的。@BenKovitz如果你觉得我关于扩展pprint的建议很有帮助,并且它们解决了你的问题,你应该添加自己的答案,解释如何扩展pprint的细节。我所说的都是些粗制滥造的话,对将来可能读到这个问题的人来说也没什么用处。(或者,如果您的意思是,我提出的扩展print方法的建议很简单,而且已经足够了,而您根本没有扩展pprint,那么请不要介意,接受我的回答)。