Let's start Scheme

2014-11-14

SRFI-38の紹介

(LISP Library 365参加エントリ)

SRFI-38は共有データの外部表現を定義したSRFIです。まずはどういうものか見てみましょう。
;; make a circular list
(define a (cons 'val1 'val2))
(set-cdr! a a)

(write-with-shared-structure a)
;; writes #1=(val1 . #1#)

(read-with-shared-structure (open-string-input-port "#1=(val1 . #1#)"))
;; -> #1=(val1 . #1#)
CLでおなじみの共有構造にラベルが付いた表現ですね。write-with-shared-structureではデータが循環せず単に共有していた場合でもラベル付きで表示します。

実はこれ以外には何もなかったりするので、以下は与太話。上記の表現はR7RSで正式に採用されたのですが、スクリプト内で使うとエラーだったりします。また通常のwriteも共有構造を検知しなければなりません。面白いのは通常のwriteは共有構造を検知してもそれが循環構造でなければ普通に表示するようになっている点です。例えば以下。
(import (scheme write))

;; This script is actually invalid, so not portable.
(write '#1=#(1 2 3 #1#))
;; writes #1=#(1 2 3 #1#)

;; ditto
(write '#(#1=(1 2 3) #1#))
;; writes #((1 2 3) (1 2 3))
どういった経緯でこうなったかは議論を追ってないので憶測ですが、R5RSとの互換性かなぁと思います。これがありがたいかといわれると、今のところ恩恵にあずかったことはなかったりします。

今回はSRFI-38を紹介しました。

2 comments:

Shiro Kawai said...

評価結果に循環構造が含まれていた場合にREPLの表示が止まらなくなると不便なので、以前のGaucheではREPLにwrite/ssを使っていたのですが、よく初心者が混乱していたみたいです。(make-list 2 '(a))の結果が((a) (a))にならないのはなぜ、といった質問を何回も受けたことがあります。また、熟練者であっても、木を意図したデータ構造なのにたまたま部分共有があって#n#表記がまざるとむしろ見にくいってのもありました。なので、r7rsの「循環構造のみ#n#表記をデフォルトにする」はなかなか良いアイディアだと思います。

kei said...

なるほど、確かにラベルの方が混乱しますね。あまり循環構造を使わない+普段からwrite/displayで共有構造を表示してたので目に見えた恩恵を預かってなかったので盲点でした。

Post a Comment