Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2011-06-19

CLでSRFI-9

| 16:32 | CLでSRFI-9 - わだばLisperになる を含むブックマーク はてなブックマーク - CLでSRFI-9 - わだばLisperになる

適当にSRFI実装をしていますが、今回は、SRFI-9 レコード型の定義 です。

CLでいう構造体かクラスですが、SRFI-9の define-record-typeも定義時にアクセサやモディファイア等を一式作成するものです。

動作

define-record-type の使い方ですが、定義は、

(define-record-type レコード名 コンストラクタ 述語 *(スロット アクセサ名 モディファイア名))

という風に記述します。

;; pairの定義
(define-record-type pair
  (kons x y)
  pair?
  (x kar set-kar!)
  (y kdr set-kdr!))

;; レコードの作成
(defvar kons (kons 1 2))

(pair? kons)
;=> T

(kar kons)
;=> 1

(kdr kons)
;=> 2

(set-kar! kons 100)
;=> 100

kons
;=> #S(PAIR :KAR 100 :KDR 2)

(set-kdr! kons 200)
;=> 200

kons
;=> #S(PAIR :KAR 100 :KDR 200)

上記のpairの定義は、下記のように展開されることにしてみました。

(progn
  (defstruct (pair
               (:constructor kons (x y &aux (kar x) (kdr y)))
               (:predicate pair?)
               (:conc-name ""))
    kar kdr)
  (srfi-9-internal::define-modifier kar set-kar!)
  (srfi-9-internal::define-modifier kdr set-kdr!))

仮引数とスロット名が対応していませんが、アクセサをdefstruct標準の機能で作成しているのでslot名=アクセサ名となっています。

コンストラクタの引数はdefstructにそのまま渡しているので、defstructのラムダリストが使えます。(これはboa lambda listと呼ばれるようです)

(define-record-type foo
  (mkfoo a b &key c)
  foo?
  (a fooa)
  (b foob)
  (c fooc))

(defvar foo (mkfoo 1 2 :c 3))
;=> FOO

foo
;=> #S(FOO :FOOA 1 :FOOB 2 :FOOC 3)

(incf (fooc foo) 100)
;=> 103

foo
;=> #S(FOO :FOOA 1 :FOOB 2 :FOOC 103)

defstructはオプションが豊富で魔窟な感じですが、こういうシンプルに使えるマクロを用意して使ってみるのもありかなと思います。