Archive for the ‘propmacro’ Tag

newLISP で On Lisp する...第16章(その1)

(この blog は、“short short story または 晴耕雨読な日々”からの引越してきたもの。スクリプトは、newLISP V10.2.1 以降で動作するように書き直しています。
defun 等の newLISP組込関数に無い関数は、特に断らない限り、newlisp-utility.lsponnewlisp.lsp に定義してあります。)

 第16章 マクロを定義するマクロ の始まりです。今回は、省略属性 を実装します。

 先ずは、省略 から。

(define addrev define)
(define addrevs setq)

 “On Lisp” 本書のマクロaddrev は、newLISPでは、マクロの必要がありません。define が使えますから(楽)。しかも、マクロaddrevs でさえ、マクロの必要がありません。マクロaddrev も、setq としても良かったのですが(笑)。
 変数と関数が、同一名前空間にある強みです。

 そして、属性 。newLISPには 属性 がありません。ましてや、関数get もありません。だから、終わりにしても良かったのですが、context で実現してみます。
 先ずは、関数get から、(defun と reference-inversionマクロ群は newlisp-utility.lsp に定義してあります。)

(defun get (symbol indicator)
  (letex (_sym (sym indicator symbol))
    (reference-inversion:set _sym)))

 newLISP組込sym を使って、symbol 名の contex に indicator名のシンボル名を作ります。そのシンボルが予めあれば、その値が表示され、無ければ nil が返ります。 reference-inversion:set は、前回も使った newLISP でインバージョン可能な参照を実現するマクロ群の一つです。
 使い方は、

> (setf (get 'ball1 'color) 'red)
red
> (get 'ball1 'color)
nil
> 

 ただの setf では、属性が設定されません。
 しかし、

> (addrevs _r reference-inversion setfr _r:setf)
(lambda-macro () 
 (letex (reference-inversion:_body (cons 'begin (map (curry append '(reference-inversion:reference-inversion 
       setf)) 
     (explode (args) 2)))) 
  (begin 
   reference-inversion:_body)))
> (setf (get 'ball1 'color) 'red)
red
> (get 'ball1 'color)
nil
> (_r setf (get 'ball1 'color) 'red)
red
> (get 'ball1 'color)
red
> (_r:setf (get 'ball1 'color) 'yellow)
yellow
> (get 'ball1 'color)
yellow
> (setfr (get 'ball1 'color) 'blue)
blue
> (get 'ball1 'color)
blue
> 

 といった具合に、reference-inversion:setfを使えば、属性が設定されます。
 表記に (_r setf …) を使うか、(_r:setf …) あるいは、(setfr …)を使うかは、お好みで(笑)。
 そして、属性を参照するマクロです。

(define-macro (color)
; (color symbol)
  (letex (_sym (sym 'color (eval (args 0))))
    (reference-inversion:set _sym)))

 使い方は、関数get と同様、

> (color 'ball1)
yellow
> (setf (color 'ball1) 'green)
green
> (color 'ball1)
yellow
> (_r:setf (color 'ball1) 'green)
green
> (color 'ball1)
green
> 

 reference-inversionマクロ群を使って、インバージョン可能なマクロになっています。
 アクセス用マクロの自動定義 は、こうなります。

(define-macro (propmacro propname)
  (letex (_propname propname)
    (setq _propname (lambda-macro ()
      (letex (_sym (sym '_propname (eval (args 0))))
        (reference-inversion:set _sym))))))

(define-macro (propmacros)
  (letex (_pair (cons 'begin (map (curry cons 'propmacro) (explode (args)))))
    _pair))

 動作は、

> color
(lambda-macro () 
 (letex (_sym (sym 'color (eval (args 0)))) (reference-inversion:set _sym)))
> (propmacros size color)
(lambda-macro () 
 (letex (_sym (sym 'color (eval (args 0)))) (reference-inversion:set _sym)))
> color
(lambda-macro () 
 (letex (_sym (sym 'color (eval (args 0)))) (reference-inversion:set _sym)))
> size
(lambda-macro () 
 (letex (_sym (sym 'size (eval (args 0)))) (reference-inversion:set _sym)))
> 

 どちらで定義しても同じです。

 アナフォリックマクロ は次回に。

 以上、如何でしょうか?