Wednesday, March 01, 2006

cl-dot

cl-dot คือ library ที่ช่วยในการ generate graphviz dot output

สมมติเรามี structure แบบนี้ใน lisp
(defstruct node name value childs)

แล้วก็มี tree ที่มีหน้าตาแบบนี้
(setq tree (make-node :name '1
:childs (list
(make-node :name '2)
(make-node :name '3
:childs (list
(make-node :name 4))))))


การใช้ cl-dot กับ structure แบบนี้
ทำได้โดยการ implement generic function
ที่ cl-dot เตรียมไว้

ส่วน generic function คืออะไร?
generic function คือ abstract operation
น่าจะเทียบได้กับ abstract method ใน java
เพียงแต่ method ของ java เป็นส่วนหนึ่งของ ojbect
ส่วน lisp method ไม่จำเป็นต้องอยู่ใน object

(note: generic method ทำอะไรได้พิสดารเชียวหล่ะ
เช่น Method combination, Multimethods
อ่านได้ใน Object Reorientation: Generic Functions
ของ Peter Seibel)

c-dot กำหนด generic function ไว้ 4 ตัว แต่เราจะลองแค่ 2 ตัวคือ
(defgeneric object-node (object)
(:documentation
"Return a NODE instance for this object, or NIL. In the latter case
the object will not be included in the graph, but it can still have an
indirect effect via other protocol functions (e.g. OBJECT-KNOWS-OF).
This function will only be called once for each object during the
generation of a graph."))

(defgeneric object-points-to (object)
(:documentation
"Return a list of objects to which the NODE of this object should be
connected. The edges will be directed from this object to the others.
To assign dot attributes to the generated edges, each object can optionally
be wrapped in a instance of ATTRIBUTED.")
(:method ((object t))
nil))


ในตัวอย่าง struture ข้างบน เราจะ implement function object-node
เนื่องจากเรามี object อยู่ชนิดเดียวใน tree จึง implement แค่ function เดียว
(defmethod cl-dot:object-node ((object node))
(make-instance 'cl-dot:node
:attributes `(:label ,(node-name object)
:shape :box)))


ในส่วนของ edge ก็ implement ผ่าน function object-points-to
(defmethod cl-dot:object-points-to ((object node))
(mapcar #'(lambda (child)
(make-instance 'cl-dot:attributed
:object child
:attributes '(:weight 3)))
(node-childs object)))

เวลา run ก็ใช้คำสั่งนี้
(cl-dot:print-graph (cl-dot:generate-graph tree))

ผลลัพท์ที่ได้
digraph {
1 [label="1",shape=box];
3 [label="3",shape=box];
4 [label="4",shape=box];
2 [label="2",shape=box];
1 -> 3 [weight=3];
1 -> 2 [weight=3];
3 -> 4 [weight=3];
}

Related link from Roti

1 comment:

Mk said...

คุณ pok ช่วยเมลหรือ IM มาหน่อยได้มั้ยครับ เผอิญมีเรื่องอยากถามนิดหน่อย

markpeak @ จีแมว