IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Visualize tree like data in Lisp

    Reverland (lhtlyy@gmail.com)发表于 2012-04-28 00:00:00
    love 0

    lisp中的特殊列表结构

    • 点状列表
    • pair
    • circular list

    可视化lisp数据

    用graphviz把lisp中数据可视化的方法,代码如下:

    ;;切换到工作目录
    (cd "/home/reverland/Documents/lisp/")
    ;;;有向图
    ;;定义节点及描述
    (defparameter *wizard-nodes* '((living-room (you are in the living-room.
    					     a wizard is snoring loudly on the couch.))
    			       (garden (you are in a beautiful garden.
    					w
    				       )
    				(attic (you are in the attic. there
    					is a giant welding torch in the corner.)))))
    ;;定义节点与边
    (defparameter *wizard-edges* '((living-room (garden west door)
    				(attic upstairs ladder))
    			       (garden (living-room east door))
    			       (attic (living-room downstairs ladder))))
      ;;转换名函数
    (defun dot-name (exp)
     (substitute-if #\_ (complement #'alphanumericp) (prin1-to-string exp)))
      ;将非字母数字的字符转化为下划线 
      ;;定义标签长度
    (defparameter *max-label-length* 30)
      ;;处理位置描述
    (defun dot-label (exp)
     (if exp
      (let ((s (write-to-string exp :pretty nil))); :pretty防止换行或加入tab
       (if (> (length s) *max-label-length*)
        (concatenate 'string 
         (subseq s 0 (- *max-label-length* 3)) "...")
        ;如果标签长度比最长值长,将超长的替换成...
        s))
      ""));strange,why not nil?
      ;;定义节点和标签函数
    (defun nodes->dot (nodes)
     (mapc (lambda (node);mapc不返回列表
    	(fresh-line)
    	(princ (dot-name (car node)))
    	(princ "[label=\"")
    	(princ (dot-label node))
    	(princ "\"];"))
      nodes))
      ;;定义遍历edges中每个元素,再对每个元素进行遍历
      (defun edges->dot (edges)
       (mapc (lambda (node)
    	  (mapc (lambda (edge)
    		 (fresh-line)
    		 (princ (dot-name (car node)))
    		 (princ "->")
    		 (princ (dot-name (car edge)))
    		 (princ "[label=\"")
    		 (princ (dot-label (cdr edge)))
    		 (princ "\"];"))
    	   (cdr node)))
        edges))
      ;;生成dot文件内容
    (defun graph->dot (nodes edges)
     (princ "digraph{")
     (nodes->dot nodes)
     (edges->dot edges)
     (princ "}"))
      ;;接受一个trunk,得到trunk的输出而非函数的值
      ;;to keep this dot->png function as reusable as possible, the graph->dot
      ;;function isn’t called directly. Instead, we write dot->png to accept a thunk
    (defun dot->png (fname thunk)
     (with-open-file (*standard-output*;类比与let
    		  fname ;输入到fname文件
    		  :direction :output;keyword symbol即本身,方向输出
    		  :if-exists :supersede);如果存在覆盖
      (funcall thunk));nully function
     (ext:shell (concatenate 'string "dot -Tpng -O " fname)))
    ;it's an O actually!it's not zero!
    ;;最后一步
    (defun graph->png (fname nodes edges)
     (dot->png fname
      (lambda ();relay funcion
       (graph->dot nodes edges))));which is the trunk,I am not clear.
      ;;最后执行
      (graph->png "wizard.dot" *wizard-nodes* *wizard-edges*)
      ;;;无方向图
    (defun uedges->dot (edges)
     (maplist (lambda (lst);遍历剩下的元素
    	   (mapc (lambda (edge)
    		  (unless (assoc (car edge) (cdr lst));除非以下不再出现这个位置
    		   (fresh-line)
    		   (princ (dot-name (caar lst)))
    		   (princ "--")
    		   (princ (dot-name (car edge)))
    		   (princ "[label=\"")
    		   (princ (dot-label (cdr edge)))
    		   (princ "\"];")))
    	    (cdar lst)))
      edges))
    (defun ugraph->dot (nodes edges)
     (princ "graph{")
     (nodes->dot nodes)
     (uedges->dot edges)
     (princ "}"))
    (defun ugraph->png (fname nodes edges)
     (dot->png fname
      (lambda ()
       (ugraph->dot nodes edges))))
      ;;执行命令
      (ugraph->png "uwizard.dot" *wizard-nodes* *wizard-edges*)

    结合上回处理文本,觉得lisp在处理列表和文本时挺方便,虽然没有正则什么的。然后学习到lisp和unix环境交互还是比较方便的。

    学会了一个生成文本数据的技术,把打印到终端而易于调试的输出包装成一个thunk,传递给其它函数。

    学到了很多命令:

    • cd(ext)
    • substitute-if
    • complement
    • alphanumericp
    • write-to-string
    • subseq
    • mapc
    • maplist
    • with-open-file
    • funcall

    参考资料

    graphivz中文使用指南



沪ICP备19023445号-2号
友情链接