- mbe 20151126.334(in MELPA)
- Macros by Example
概要
mbe.el は Scheme の パターンマッチ のようなことができます。
SRFI 46 / R6RS スタイルのパターンが使えます。
(<pattern> ...) (<pattern> <pattern> ... . <pattern>) (<pattern> ... <pattern> <ellipsis>) (<pattern> ... <ellipsis> <pattern> ...) (<pattern> ... <ellipsis> <pattern> ... . <pattern>)
インストール
パッケージシステムを初めて使う人は
以下の設定を ~/.emacs.d/init.el の
先頭に加えてください。
(package-initialize) (setq package-archives '(("gnu" . "http://elpa.gnu.org/packages/") ("melpa" . "http://melpa.org/packages/") ("org" . "http://orgmode.org/elpa/")))
初めてmbeを使う方は
以下のコマンドを実行します。
M-x package-install mbe
アップグレードする方は、
以下のコマンドでアップグレードしてください。
そのためにはpackage-utilsパッケージが必要です。
M-x package-install package-utils (初めてアップグレードする場合のみ) M-x package-utils-upgrade-by-name mbe
パターンマッチ結果をローカル変数にするmbe-bind
パターンマッチを行うマクロは mbe-bind です。
(mbe-bind Patパターン 値 フォーム...)
の書式になります。
使用例 141222083004.el(以下のコードと同一)
;;; これは単純なパターンでaとbにはそれぞれ1と2が入る (mbe-bind (a b) '(1 2) a ; => 1 b ; => 2 ) ;;; シンボル...は直前のパターンの繰り返し ;;; b ...でリストの残りを表す (mbe-bind (a b ...) '(1 2 3 4 5) a ; => 1 b ; => (2 3 4 5) ) ;;; パターン (a b) の繰り返しを表す暗黙のループ (mbe-bind ((a b) ...) '((a 1) (b 2) (c 3)) a ; => (a b c) b ; => (1 2 3) ) ;;; ネストした... ;;; aは最初の要素、bは残りの要素になる (mbe-bind ((a b ...) ...) '((a 1 "alpha" "beta") (b 2) (c 3 "gamma")) a ; => (a b c) b ; => ((1 "alpha" "beta") (2) (3 "gamma")) ) ;;; 最後の3 2 1がマッチしている (mbe-bind (a b c ... 3 2 1) '(7 6 5 4 3 2 1) a ; => 7 b ; => 6 c ; => (5 4) ) ;;; dとeは最後の2要素になる (mbe-bind (a b c ... d e) '(1 2 3 4 5 6 7 8 9) a ; => 1 b ; => 2 c ; => (3 4 5 6 7) d ; => 8 e ; => 9 ) ;;; リストの最後のコンスセルのcdrはnilなのでfはnil (mbe-bind (a b c ... d e . f) '(1 2 3 4 5 6 7 8 9) a ; => 1 b ; => 2 c ; => (3 4 5 6 7) d ; => 8 e ; => 9 f ; => nil ) ;;; 最後のコンスセルが9 (mbe-bind (a b c ... d e . f) '(1 2 3 4 5 6 7 8 . 9) a ; => 1 b ; => 2 c ; => (3 4 5 6) d ; => 7 e ; => 8 f ; => 9 )
パターンマッチを使ってマクロを記述する
mbe-defrules マクロはSchemeの syntax-rules や
syntax-case のような形でマクロを定義します。
パターンマッチの方法はmbe-bindと同じです。
incfを定義 141222084410.el(以下のコードと同一)
(mbe-defrules my-incf ;; 引数が1つのときは1足す ((var) (setq var (+ var 1))) ;; 引数が2つのときはby足す ((var by) (setq var (+ var by)))) (let ((a 0) (b 0)) (incf a) ; => 1 (incf a 10) ; => 11 a ; => 11 (my-incf b) ; => 1 (my-incf b 10) ; => 11 b ; => 11 )
pushを定義 141222084700.el(以下のコードと同一)
;;; 冗長な記法 (mbe-defrules my-push1 ((newelt place) (setq place (cons newelt place)))) ;;; 引数の形式が1つなのでシンプルな記法でよい (mbe-defrule my-push2 (newelt place) (setq place (cons newelt place))) (let (x y z) (push 1 x) ; => (1) x ; => (1) (my-push1 1 y) ; => (1) y ; => (1) (my-push2 1 z) ; => (1) z ; => (1) )
letを定義 141222084905.el(以下のコードと同一)
(mbe-defrule mylet (((var val) ...) body ...) (funcall (lambda (var ...) body ...) val ...)) (mylet ((a 1) (b 2)) a ; => 1 b ; => 2 (+ a b)) ; => 3
本日もお読みいただき、ありがとうございました。参考になれば嬉しいです。