Scheme/R6RS/翻訳/7.ライブラリ


Top / Scheme / R6RS / 翻訳 / 7.ライブラリ

これは何か?

R6RS http://www.r6rs.org/ の必要な箇所をひげぽんが翻訳したものです。
誤訳の指摘などはコメントにお願いします。
→現在この翻訳はR6RS:翻訳:R6RS:Librariesに移動してそこでメンテナンスされています。

7. ライブラリ

ライブラリとは独立して配布することのできるプログラムのパーツである。
ライブラリシステムはライブラリ内でのマクロ定義、マクロのエクスポート、定義やインポートが必要なフェーズを指定する機能を提供する。
この章ではライブラリの表記法とライブラリの展開と実行の意味論を定義する。

7.1. ライブラリフォーム

ライブラリ定義は以下のフォームを持たなければいけない。(must)

(library <library name>
  (export <export spec> ...)
  (import <import spec> ...)
  <library body>)

ライブラリ宣言は以下の要素からなる。



それぞれのライブラリからエクスポートされたその束縛が全く同じ場合(すなわち1つのライブラリで束縛が定義されそれがエクスポートや再エクスポートによりインポートされることで他のライブラリに到達している場合)に限り、識別子を同じローカル名で2つ以上のライブラリからインポートしたり、同じライブラリから2つのレベルでインポートすることができる。
上記にあてはまらない場合に識別子が複数回インポートされたり定義されたりまたはその両方が起こることはありえない。
ライブラリ内で明示的に定義されたりインポートされない限りは識別子がライブラリ内で可視になることはない。
<library name> はその実装内でライブラリを一意に特定し、その他すべてのライブラリの import 節(下に説明がある) においてグローバルに可視である。
<library name> は以下のフォームを持つ。

(<identifier1> <identifier2> ... <version>)

<version> は空もしくは以下のフォームを持つ。

(<sub-version> ...)

どの <sub-version> も正確な非負の整数オブジェクトでなければならない(must)。空の <version> は () と等価である。

<export spec> はインポートされた束縛やローカルに定義された束縛のうちエクスポートするものに名前をつける。場合によっては違う外部名になることもある。
<export spec> は以下のうちどれか1つのフォームを持たなければならない。(must)

<identifier>
(rename (<identifier1> <identifier2>) ...)

<export spec> において <identifier> はライブラリの中で定義されたりインポートされた1つの束縛に名前をつける。エクスポートする時の外部名はライブラリの中での名前と同じである。
rename はそれぞれの(<identifier1> <identifier2>)ペアに対して <identifier1>と名前をつけられた束縛を <identifier2> という外部名でエクスポートする。
それぞれの<import spec>はライブラリにインポートされる束縛のセットを指定し、どのレベルでそれらが利用可能になるかを指定し、どのようなローカル名を持つかを指定する。
<import spec> 以下のうちどれか1つでなければならない(must):

 <import set>
 (for <import set> <import level> ...)

<import level> 以下のうちいずれかである:

run
expand
(meta <level>)

<level> は正確な整数オブジェクトである。
<import level>で考えれば run は (meta 0)、expand は (meta 1) の略記である。
レベルとフェーズはセクション7.2 で議論する。
<import set> は別のライブラリからの束縛セットに名前をつける、インポートされた束縛にローカル名を指定することもある。
以下のうちどれか1つでなければならない(must):

<library reference>
(library <library reference>)
(only <import set> <identifier> ...)
(except <import set> <identifier> ...)
(prefix <import set> <identifier>)
(rename <import set> (<identifier1> <identifier2>) ...)

<library reference> はライブラリの名前と任意のバージョンによってライブラリを特定する。
<library reference> は以下のうち1つのフォームを持つ:

(<identifier1> <identifier2> ...)
(<identifier1> <identifier2> ... <version reference>)

1つめの <identifier> が for、library、only、except、prefix、rename である <library reference> は ライブラリの <import set> 内でのみ許される。
それ以外の場合は <import set>である(library <library reference> )は <library reference> と等価である。
<version reference> を持たない <library reference> (上の1つめのフォーム)は <version reference> が () の <library reference> と等価である。
<version reference> はライブラリがマッチする <version> のセットを指定する。
<library reference> は同じ名前を持ち <version reference> にマッチするすべてのライブラリを特定する。
<version reference> は以下のフォームを持つ:

(<sub-version reference1> ... <sub-version referencen>)
(and <version reference> ...)
(or <version reference> ...)
(not <version reference>)

1つめのフォームの <version reference> は少なくとも n 要素の <version> とマッチする。<version> はそれぞれの <sub-version reference> は一致する <sub-version> にマッチする。
and <version reference> は and に続くすべての <version reference> にマッチしたときにマッチする。
同様に or <version reference> では or に続く <version reference> のうち1つにマッチしたとき、not <version reference> では続く <version reference> がマッチしない時にマッチする。
<<sub-version reference> 以下のうち1つのフォームを持つ:

<sub-version>
(>= <sub-version>)
(<= <sub-version>)
(and <sub-version reference> ...)
(or <sub-version reference> ...)
(not <sub-version reference>)

1つめのフォームの <sub-version reference>は <sub-version>とライブラリの <sub-version> が等しいときにマッチする。
>= はそれに続く<sub-version> よりもライブラリの <sub-version> が大きいか等しい場合にマッチする。 <= も同じ仕組みである。
and <sub-version reference> は後に続く <sub-version reference>がすべてマッチするときにマッチする。
同様に or <sub-version reference> は後に続く <sub-version> の中で1つがマッチすれば、 not <sub-version reference> は後に続く <sub-version> がマッチしなければマッチする。
例:

version referenceversionマッチするか?
()(1)yes
(1)(1)yes
(1)(2)no
(2 3)(2)no
(2 3)(2 3)yes
(2 3)(2 3 5)yes
(or (1 (>= 1)) (2))(2)yes
(or (1 (>= 1)) (2))(1 1)yes
(or (1 (>= 1)) (2))(1 0)no
( (or 1 2 3))(1)yes
( (or 1 2 3))(2)yes
( (or 1 2 3))(3)yes
( (or 1 2 3))(4)no

library reference によって2つ以上のライブラリが特定された場合は、どのライブラリを選択するかは実装に依存して決定される。
不完全な型や、複製された状態のような問題を避けるために、実装は2つのライブラリが同じ識別子の並びを持つ一方で同じプログラム内で共存できないバージョンであるような状況を禁止すべきである。
デフォルトではインポート元のライブラリからインポートしたライブラリがエクスポートしている束縛はすべて可視となっている。その際にはインポートしたライブラリから与えられた名前を介して可視となっている。
インポートされる束縛の明確なセットとこれらの束縛の名前は以下に述べる only、except、prefix、rename フォームによって調整することができる。

ライブラリフォームの <library body> は定義(definitions)もしくは式(expressions)に分類されるフォームで構成される。
あるフォームがどちらに分類されるかはインポートされたライブラリや展開の結果に依存する。- 10章を見よ。
一般的に定義でないもの(セクション11.2のベースライブラリで利用可能な定義を見よ)は式である。
<library body> が式を含む必要がない点を除けば、<library body> は <body>(セクション11.3を見よ)と同じである。
<library body> は以下のフォームを持たなければならない(must):

<definition> ... <expression> ...

最初に現れる式よりも begin、let-syntax、もしくは letrec-syntax フォームがトップレベル body がある場合、それらは body に挿入される(セクション11.4.7を見よ)。
begin、let-syntax、letrec-syntax にラップされた部分式を含むいくつかまたは全ての body は構文抽象(syntactic abstraction) によって定められる。(セクション9.2を見よ)
10章で説明される通り変換式と束縛は左から右に評価され作られる。
変数定義の式は暗黙の letrec* にあるかのように左から右に評価される。また body 式も変数定義の式の評価の後に左から右に評価される。
エクスポートされた変数のそれぞれに対して未使用の場所が作られ、ローカルの対応する変数の値に初期化される。
一番最後の body 式の継続に2回戻ってくる場合の作用は不定である。
注意:ライブラリ構文の中に現れる library、 export、 import、 for、 run、 expand、meta、 import、 export、 only、 except、 prefix、 rename、 and、 or、not、 >=、<= などの名前は構文の一部であり予約されているわけではない。すなわちそれらと同じ名前をライブラリフォームでの使用に影響を与えず、ライブラリ内で別の目的で使うこともできるし、その名前をライブラリにエクスポートしたりインポートすることもできる。

明示的にライブラリからエクスポートされない限り、ライブラリで定義された束縛はライブラリの外では見えない。
しかしながらエクスポートされたマクロによってライブラリ内で定義されたりインポートされた識別子が意図せずエクスポートされることがあるかもしれない。
つまりマクロは生成するコードにその識別子へのリファレンスを挿入するかもしれないということである。
全てのエクスポートされた変数はエクスポート先とインポート先のライブラリで不変(immutable)である。
従ってもしもエクスポート先もしくはインポート先のライブラリで明示的にインポートされた変数が set! 式の左側に現れた場合は構文違反である。
同様に暗黙にエクスポートされた変数はエクスポート先とインポート先のライブラリで不変である。
従ってライブラリ内で定義された変数がエクスポートされたマクロで生成されたコードの中で set! 式の左側に現れた場合は構文違反である。
同様にライブラリ内で定義された変数が、エクスポートされたマクロで生成されたコードの中で代入された変数への参照が現れた場合は構文違反である。代入された変数とはエクスポート先のライブラリで set! 式の左側に現れる変数の事である。
ライブラリ内で定義されたその他の変数はすべて可変(mutable)である。

7.2 インポート・エクスポートレベル

ライブラリの展開には別のライブラリの実行時情報が必要なことがある。
例えばマクロ変換器*1がライブラリ A の手続きを呼んでいる場合、ライブラリ B 内で使われているそのマクロを展開する前にライブラリ A のインスタンスが作られていなければならない(must)。

ライブラリ B が最終的にプログラムの一部として実行される場合はライブラリ A は必要ないかもしれないし、ライブラリ B の実行時にライブラリ A は必要とされるかもしれない。
ライブラリ機構はこれらをフェーズを利用して区別する。フェーズについてはこのセクションで説明する。

全てのライブラリは展開時情報(最低限の情報としてインポートしているライブラリ、エクスポートしているキーワードのリスト、エクスポートしている変数のリスト、変換式を評価するためのコード)と実行時情報(最低限の情報として変数定義の右側の式を評価するためのコード、 body 式を評価するためのコード)によって説明できるだろう。
展開時情報はエクスポートされている束縛の参照を展開するときに利用可能でなければならない。実行時情報はエクスポートされている変数束縛へ参照を評価する時に利用可能でなければならない(must)。

フェーズとはライブラリ内にある式が評価されるタイミングのことである。
ライブラリの body 、トップレベル式、define フォームの右側は実行時すなわち フェーズ 0 で評価される。define-syntax フォームの右側は展開時すなわち フェーズ 1で評価される。
define-syntax、let-syntax、もしくは letrec-syntax フォームが フェーズ n で評価されるコードに現れた場合、そのフォームの右側は フェーズ n+1 で評価される。

これらのフェーズはライブラリ自身が使われるフェーズと相対関係にある。
ライブラリのインスタンス(instance)とは別のライブラリと相対的な特定のフェーズでそのライブラリの変数定義、式が評価されることに相当する。このプロセスはインスタンス化と呼ばれる。
例えばライブラリ B のトップレベル式が別のライブラリ A がエクスポートしている変数を参照している場合、その式は フェーズ 0(Bのフェーズと相対的である)でライブラリ A のインスタンスからエクスポートを参照する。
しかしもしも B 内で フェーズ 1 の式が A の同じ束縛を参照した場合、フェーズ 1 (Bのフェーズと相対的である)で A のインスタンスからエクスポートを参照する。

ライブラリの訪問(visit)とは別のライブラリと相対的な特定のフェーズで構文定義を評価することに相当する。このプロセスは visiting と呼ばれる。
例えばライブラリ B のトップレベル式が別のライブラリ A がエクスポートしているマクロを参照している場合、その式は フェーズ 0(Bのフェーズと相対的である)でライブラリ A の訪問からエクスポートを参照する。これは フェーズ 1 でマクロ変換式をを評価することに一致する。

レベルとは識別子の字句特性でその識別子がどのフェーズで参照されるかを決定するものである。
ライブラリ内で定義によって束縛される識別子のレベルは 0 である。つまり識別子はライブラリ内で フェーズ 0 のときにのみ参照可能である。

インポートされた束縛のレベルは、エクスポート先のライブラリの識別子のレベルに加えてインポート先のライブラリにおいて外側をとりかこむ for フォームによって決まる。

インポートやエクスポートのレベルは全てのレベルの組み合わせの対のたし算によって組み合わせられる。*2
例えばレベル pa と pb でエクスポートされ、レベル qa、qb、qc でエクスポートされるインポートされた識別子への参照はレベル pa+qa, pa+qb, pa+qc, pb+qa, pb+qb, pb+qc において有効である。
外側にとりかこむ for を持たない <import set> は (for <import set> run) と等価であり (for <import set> (meta 0)) とも等価である。

エクスポート先のライブラリで定義された全ての束縛に対するエクスポートレベルは 0 である。
再エクスポートされた束縛、すなわち別のライブラリからインポートされたものをエクスポートした場合のエクスポートレベルは再エクスポート先のインポートレベルと同じである。
ライブラリレポートで定義されてライブラリではほぼすべての束縛のエクスポートレベル 0 である。
例外は (rnrs base (6)) ライブラリでレベル 1でエクスポートされている syntax-rules、identifier-syntax、_ 。
それと (rnrs base (6)) ライブラリでレベル 0 と 1 でエクスポートされている set! 。
それと合成 (rnrs (6)) ライブラリ(15章ライブラリを見よ)ででレベル 0 と 1 でエクスポートされている全ての束縛である。

ライブラリ内のマクロの展開はライブラリにインポートされた識別子への参照を暗黙的に取り入れる可能性がある。
その場合、その参照のフェーズはソースライブラリのフェーズ(識別子の字句コンテキストを提供するライブラリ)と参照を取り囲むライブラリのフェーズの違いによって変化する識別子のレベルにマッチしなければならない。
例えば、ライブラリの展開がマクロ変換器*3を引き起こし、マクロ変換器*4の評価が別のライブラリがエクスポートしている識別子を参照すると仮定する(つまりそのライブラリの フェーズ 1 のインスタンスが使われる)。
さらにその束縛の値がレベル n の束縛によってのみの識別子を表現した構文オブジェクトであったと仮定すると、その識別子は展開中のライブラリのフェーズ n + 1 においてのみ使用される(must)。

たとえライブラリは非負のフェーズでのみ存在していても識別子の負のレベルが有用なのは、このレベルとフェーズの組み合わせがあるからである。

プログラムの展開されたフォームの中でライブラリの定義がフェーズ 0 で参照された場合、そのプログラムの定義や式が展開される前に参照されたライブラリのインスタンスがフェーズ 0 用に作成される。
このルールは推移的に適用される。あるライブラリの展開されたフォームが別のライブラリの識別子をフェーズ 0 で参照する場合、フェーズ n で参照するライブラリがインスタンス化される前に参照されるライブラリがフェーズ n でインスタンス化されなければならない(must)。
対照的に識別子が 0 よりも大きいフェーズで参照される場合は、定義先のライブラリのインスタンス化は参照が評価される前の不定なタイミングでフェーズ n で行われる。
同様にライブラリの展開の最中にマクロキーワードがフェーズ n で参照される場合は定義先のライブラリの訪問(visit)は参照が評価される前の不定なタイミングでフェーズ n で行われる。
実装は異なるフェーズにおけるライブラリのインスタンス/訪問(visit)を区別するだろう。また任意のフェーズのインスタンス/訪問(visit)の仕様を別ののフェーズのインスタンス/訪問(visit)と区別するだろう。((自信無))
実装はフェーズ 0 よりも大きなフェーズのライブラリの and/or インスタンスの中で区別できるライブラリの訪問(visit)をしライブラリフォームを展開してもよい。*5

また実装は参照を満たすために必要とされるより多くのフェーズでより多くのインスタンス/訪問を作っても良い。
識別子が自身のレベルと矛盾するフェーズの式として現れた場合、実装は展開時もしくは実行時に例外を上げても良いし、参照を許しても良い。
従ってフェーズ間もしくはライブラリ展開をまたがってライブラリのインスタンスが区別されるか、共有されるかに依存するようなライブラリはポータブルではなくなるであろう。

7.3. 例

<import spec>、<export spec> の様々な例。

(library (stack)
 (export make push! pop! empty!)

 (import (rnrs))
 (define (make) (list ’()))
 (define (push! s v) (set-car! s (cons v (car s))))
 (define (pop! s) (let ([v (caar s)])
                    (set-car! s (cdar s))
                    v))
 (define (empty! s) (set-car! s ’())))

(library (balloons)
 (export make push pop)
 (import (rnrs))
 (define (make w h) (cons w h))
 (define (push b amt)
   (cons (- (car b) amt) (+ (cdr b) amt)))
 (define (pop b) (display "Boom! ")
   (display (* (car b) (cdr b)))
   (newline)))
(library (party)
;; Total exports:
;; make, push, push!, make-party, pop!
 (export (rename (balloon:make make)
                 (balloon:push push))
         push!
         make-party
         (rename (party-pop! pop!)))
 (import (rnrs)
         (only (stack) make push! pop!) ; not empty!
         (prefix (balloons) balloon:))
 ;; Creates a party as a stack of balloons,
 ;; starting with two balloons
 (define (make-party)
   (let ([s (make)]) ; from stack
     (push! s (balloon:make 10 10))
     (push! s (balloon:make 12 9))
     s))
 (define (party-pop! p)
   (balloon:pop (pop! p))))
(library (main)
 (export)
 (import (rnrs) (party))
 (define p (make-party))
 (pop! p) ; displays "Boom! 108"
 (push! p (push (make 5 5) 1))
 (pop! p)) ; displays "Boom! 24"

マクロとフェーズの例:

(library (my-helpers id-stuff)
 (export find-dup)
 (import (rnrs))
 (define (find-dup l)
   (and (pair? l)
        (let loop ((rest (cdr l)))
          (cond
           [(null? rest) (find-dup (cdr l))]
           [(bound-identifier=? (car l) (car rest))
            (car rest)]
           [else (loop (cdr rest))])))))
(library (my-helpers values-stuff)
 (export mvlet)
 (import (rnrs) (for (my-helpers id-stuff) expand))
 (define-syntax mvlet
   (lambda (stx)
     (syntax-case stx ()
       [( [(id ...) expr] body0 body ...)
        (not (find-dup (syntax (id ...))))
        (syntax
         (call-with-values
             (lambda () expr)
           (lambda (id ...) body0 body ...)))]))))
(library (let-div)
 (export let-div)
 (import (rnrs)
         (my-helpers values-stuff)
         (rnrs r5rs))
 (define (quotient+remainder n d)
   (let ([q (quotient n d)])
     (values q (- n (* q d)))))
 (define-syntax let-div
   (syntax-rules ()
     [( n d (q r) body0 body ...)
      (mvlet [(q r) (quotient+remainder n d)]
             body0 body ...)])))

コメント

コメントはありません。 コメント/Scheme/R6RS/翻訳/7.ライブラリ?

お名前:

MENU

now: 6

リンク


最新の20件
2018-10-07 2018-09-20 2018-09-03 2018-05-09 2017-09-29 2017-01-10 2016-12-11 2016-10-04 2016-08-14 2016-05-29 2015-12-28 2013-02-25 2013-02-21 2013-02-20 2013-02-12 2013-02-11 2013-02-10
最新の20件
2010-02-01 2010-01-31 2010-01-30 2010-01-29 2010-01-16

Counter: 3018, today: 4, yesterday: 2

*1 訳語どうしよう
*2 自信無
*3 訳語
*4 訳語
*5 自信無

リロード   新規 編集 凍結 差分 添付 複製 改名   トップ 一覧 検索 最終更新 バックアップ   ヘルプ   最終更新のRSS

Last-modified: 2008-03-28 (金) 15:48:00 (3978d);  Modified by mona
PukiWiki 1.4.6 Copyright © 2001-2005 PukiWiki Developers Team. License is GPL.
Based on "PukiWiki" 1.3 by yu-ji
Powered by PHP 5.2.17
HTML convert time to 0.054 sec.