読者です 読者をやめる 読者になる 読者になる

SXML

Scheme処理系で図形を出力したい場合、どの形式が便利か考えるとSVGは実に良い選択である。それはS式とXMLの類似性によるところが大きい。
さて、そう頻繁にではないが、私ははてなダイアリキーワードで関心のあるキーワードから興味深い記事が無いか探してみることがある。今回はキーワード「Gauche」でダラダラと読んでいたところ、GaucheSVGの出力を試みている記事を見付けた。
id:wagavulin:20071226:1198681098
ところが、これはS式の力を活かせているとは言えない。とりあえず直線が描ければよいということなので手抜きしたのかもしれないが、Scheme(LISP)の世界でXMLを扱うのであればSXMLという表現形式は知っておくべきだろう。SXMLはXML表現をそのままS式で表現する形式であり、GaucheでもSXMLを使う為の関数群が用意されている。
信奉者の中には「そもそも何故XMLなんか制定したんだ?S式があれば充分だろう?」と主張する者も少なくない。私自身はXMLの意義を否定しないが、SXMLが便利な存在であることもまた事実である。
ウェブ検索すれば思いの他たくさんの情報が引っかかるのでここでは詳細は述べず、SVGの直線を描くのに必要な関数等を私なりにまとめてみるだけに留める。

(use sxml.tools)
(use text.tree)

(define-class <svg:point> ()
  ((x :init-value 0.0 :init-keyword :x :accessor x-of)
   (y :init-value 0.0 :init-keyword :y :accessor y-of)))

(define (point x y) (make <svg:point> :x x :y y))

(define (svg:write sxml)
  (write-tree
   `("<?xml version='1.0'?>"
     ,@(sxml:sxml->html
        `(svg (@ (xmlns "http://www.w3.org/2000/svg"))
              ,sxml)))))

(define-method svg:line ((p1 <svg:point>)
                         (p2 <svg:point>))
  `(line (@ (x1 ,(x-of p1))
            (y1 ,(y-of p1))
            (x2 ,(x-of p2))
            (y2 ,(y-of p2))
            (stroke "black"))))

実際の使い方の例を以下に示す。

(svg:write
 (list
  (svg:line (point 20 60) (point 10 5))
  (map (lambda(x)
         (apply
          (lambda(a b c d)
            (svg:line (point a b)
                      (point c d))) x))
       '((50 200 100 60)
         (60 300 10 200)))))

このコードによって、3本の直線をあらわすSVG形式の図が出力される。この例はあえてまわりくどい表現にしているが、通常のschemeの関数と自然に馴染んでいる様子を表現したかったからである。
Document ID: 3274c5b0317f1a7eef14feb6bfbc28dc