gauche util.match メモ

gauche の util.match で、束縛する必要が無いパターンには「_」を使うとよいことを shiro さんに教えていただいた。
(http://practical-scheme.net/chaton/gauche/a/2010/05/30 あたり)

util.match のリファレンスはこちら。
http://practical-scheme.net/gauche/man/gauche-refj_164.html#SEC466

「_」を使うとどのくらい違うかを手元のコードで比較してみた。

(define m 
  (macroexpand 
   '(match (list s e c d val)
      ((s e #((:CONST) n rest ...) d val)
       (vmloop s e (+ pc 2) d n))
      ((s e #((:CONSTI n) rest ...) d val)
       (vmloop s e (+ pc 1) d n))
      ((s e #((:CONSTI-PUSH n) rest ...) d val)
       (vmloop (cons n s) e (+ pc 1) d val))

      ((s e #((:GREF) var rest ...) d val)
       (vmloop s e (+ pc 2) d (lookup-global var)))

      ((s e #((:PUSH) rest ...) d val)
       (vmloop (cons val s) e (+ pc 1) d val))
      ((s e #((:NUMADDI num) rest ...) d val)
       (vmloop s e (+ pc 1) d (+ num val)))
      ((s e #((:NUMSUBI num) rest ...) d val)
       (vmloop s e (+ pc 1) d (- num val)))
      (((v . s) e #((:NUMMUL2) rest ...) d val)
       (vmloop s e (+ pc 1) d (* v val)))

      (((a . s) e #((:BNGT) then rest ...) d val)
       (if (> val a)
           (vmloop s e then d val)
           (vmloop s e (+ pc 2) d val)))

      ((s e #((:CLOSURE) body rest ...) d val) ;; todo
       (vmloop () e (+ pc 2) d (cons e body)))

      ((s e #((:PRE-CALL procedure-id) location rest ...) d val)
       (vmloop s e (+ pc 2) (cons (cons location  val) d) val))

      ((s e #((:RET) rest ...) d val)
       ;; todo
       #f
       )

      ((s e c d val)
       (format #t ";; base case: s: ~s e: ~s c: ~s d: ~s val: ~s pc: ~s~%"
               s e (subseq c 0 1) d val pc))
      )))

(define m_
  (macroexpand 
   '(match (list s e c d val)
      ((s e #((:CONST) n _ ...) d val)
       (vmloop s e (+ pc 2) d n))
      ((s e #((:CONSTI n) _ ...) d val)
       (vmloop s e (+ pc 1) d n))
      ((s e #((:CONSTI-PUSH n) _ ...) d val)
       (vmloop (cons n s) e (+ pc 1) d val))

      ((s e #((:GREF) var _ ...) d val)
       (vmloop s e (+ pc 2) d (lookup-global var)))

      ((s e #((:PUSH) _ ...) d val)
       (vmloop (cons val s) e (+ pc 1) d val))
      ((s e #((:NUMADDI num) _ ...) d val)
       (vmloop s e (+ pc 1) d (+ num val)))
      ((s e #((:NUMSUBI num) _ ...) d val)
       (vmloop s e (+ pc 1) d (- num val)))
      (((v . s) e #((:NUMMUL2) _ ...) d val)
       (vmloop s e (+ pc 1) d (* v val)))

      (((a . s) e #((:BNGT) then _ ...) d val)
       (if (> val a)
           (vmloop s e then d val)
           (vmloop s e (+ pc 2) d val)))

      ((s e #((:CLOSURE) body _ ...) d val) ;; todo
       (vmloop () e (+ pc 2) d (cons e body)))

      ((s e #((:PRE-CALL procedure-id) location _ ...) d val)
       (vmloop s e (+ pc 2) (cons (cons location  val) d) val))

      ((s e #((:RET) _ ...) d val)
       ;; todo
       #f
       )

      ((s e c d val)
       (format #t ";; base case: s: ~s e: ~s c: ~s d: ~s val: ~s pc: ~s~%"
               s e (subseq c 0 1) d val pc))
      )))

m は(無駄に)rest を使っているもの、m_ は「_」を使って改善したもの。m はかなり巨大な、ちょっと pretty print などで表示するのもためらわれる大きさになっている。flatten で要素に分解して数えてみると、以下のように大きな差が出る。

gosh> (length (flatten m))
513176
gosh> (length (flatten m_))
991

パターンマッチマクロは便利なので、ちゃんとリファレンスマニュアルを読んで適切に使おう。