#:g1: YTools: Facilities for Setting and Matchingの紹介

Posted 2014-11-30 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の335日目です。

YTools: Facilities for Setting and Matchingとはなにか

 YTools: Facilities for Setting and Matchingは、Drew McDermott氏のユーティリティであるYtoolsの中の代入とパタンマッチのユーティリティです。

パッケージ情報

パッケージ名YTools: Facilities for Setting and Matching
Quicklisp×
プロジェクトページHome page for Drew McDermott
CLiKiCLiki: YTools

インストール方法

 上記プロジェクトページからダウンロードしてきて適当に導入します。

試してみる

 代入とパタンマッチの構文ですがsetterに含まれています。

!=

 !=は、setfの拡張版とのことなので、拡張されたところを紹介してみますが、まず多値を受ける構文があります、

(let (x y)
  (!= < x _ y > (values 1 2 3))
  (list x y))
;=>  (1 3)

<と>で囲みますが、_で無視することもできます。
似たような構文ですが、括弧が付くと、リストの部分にマッチさせられます。

(let ((u (*:iota 10))
      x y z)
  (!= (< _ _ _ _ _ x y z >) u)
  (list x y z))
;=>  (5 6 7)

(let ((u (*:iota 10)) x y z) (!= (< _ _ _ _ _ x y z >) u) (list x y z))

さらに、アナフォリックマクロ的な動作も可能で、*-*という変数が読み出して来た値になるので、こんな事も可能です。

(let ((u (*:iota 10)))
  (!= (elt u 8) (list *-*))
  u)
;=>  (0 1 2 3 4 5 6 7 (8) 9)

Common Lispだと

(let ((u (*:iota 10)))
  (setf (elt u 8) (list (elt u 8)))
  u)

と書かなくてはいけないので便利といえば便利ですね。ちなみにTAOだと

(let ((u (*:iota 10)))
  (!!list !(elt u 8))
  u)
;=>  (0 1 2 3 4 5 6 7 (8) 9)

と書けたりします。

matchq、match-cond、match-let

 次にパタンマッチですが、基本構文としてmatchqがあり、他はこれの上に構築されています。
最後のqは、setqから来ているようですが、matchqはマッチ状況を真偽値で返す代入構文で、全体のマッチは失敗しても成功した部分は代入されたりします。

(let ((u '(1 2 3))
      x)
  (matchq (?x 2 3) u)
  x)
;=>  1

(let ((u '(1 2 3 4 5 nil)) x y z) (matchq (?x ?@y ?z) u) (list x y z)) ;=> (1 (2 3 4 5) 6)

?や@はリーダーマクロですが、パタン変数を表しています。
パタンマッチということでいつものharropifyを書いてみます。
ガード等の記法がやや独特ですが、記述できることは色々あります(詳細はマニュアル参照のこと)

(defun harropify (x)
  (match-cond x
    (:? (?Op ?A ?B)
        (h Op (harropify A) (harropify B)))
    (T x)))

(defun h (op a b) (match-cond (list op a b) (:? (+ ?(:+ ?M numberp) ?(:+ ?N numberp)) (+ M N)) (:? (+ 0 ?F) F) (:? (+ ?F 0) F) (:? (+ ?M (+ ?N ?O)) (h '+ (h '+ M N) O)) (:? (* ?(:+ ?M numberp) ?(:+ ?N numberp)) (* M N)) (:? (* 0 ?_) 0) (:? (* ?_ 0) 0) (:? (* ?F 1) F) (:? (* 1 ?F) F) (:? (* ?M (* ?N ?O)) (h '* (h '* M N) O)) (T (list Op A B))))

(harropify '(* x (+ (+ (* 12 0) (+ 23 8)) y))) ;=> (* X (+ 31 Y))

(dotimes (i (expt 10 7)) (harropify '(* x (+ (+ (* 12 0) (+ 23 8)) y)))) ;=> NIL #|------------------------------------------------------------| Evaluation took: 1.291 seconds of real time 1.300000 seconds of total run time (1.300000 user, 0.000000 system) 100.70% CPU 4,249,425,870 processor cycles 3,359,990,288 bytes consed

Intel(R) Xeon(R) CPU E3-1230 v3 @ 3.30GHz |------------------------------------------------------------|#

こんな感じですが、optimaが1.130secだったので結構速い方だと思います。

 この他、定番のmatch-letもあります。

(match-let (?x ?y (?(:+ ?z numberp))) '(1 2 (3))
  (list x y z))
;=>  (1 2 3)

まとめ

 今回は、YTools: Facilities for Setting and Matchingを紹介してみました。
結構独自色の強い部分でしたが馴れれば便利なこともありそうです。

comments powered by Disqus