キーワードは、自動的に自分自身に束縛されるシンボルのサブタイプです。 名前つき引数(キーワード引数)や、キーワード-値のリストで広く使われて います。
Gaucheにおけるキーワード引数のサポートについては手続きを作るを、
また独自にキーワード-値リストをパーズする方法については
let-keywords
マクロ(省略可能引数のパージング) も参照して下さい。
キーワードはかつてはシンボルと独立した型でしたが、それは
:
で始まる識別子もシンボルとして読まれるR7RSとは非互換でした。
そこで、0.9.5からGaucheは二つのモードを持つようになりました。
キーワードとシンボルが別の型になるモードと、キーワードがシンボルのサブタイプになる
モードです。
これらのモードは環境変数によって切り替えられます。
環境変数GAUCHE_KEYWORD_DISJOINT
がgosh
起動時に定義されていたら、
キーワードとシンボルは別の型になります。
そうでなく、環境変数GAUCHE_KEYWORD_IS_SYMBOL
が定義されていたら、
キーワードはシンボルのサブタイプになります。
どちらの環境変数も定義されていない場合のデフォルトの動作は、0.9.8で変更になりました。
0.9.7以前はGAUCHE_KEYWORD_DISJOINT
の動作がデフォルトですが、
0.9.8以降はGAUCHE_KEYWORD_IS_SYMBOL
がデフォルトになっています。
ほとんどの典型的なコードはどちらのモードでも動きますが、 異なる振る舞いをするコードもあります。 二つのモードの違いについてはキーワードとシンボルの統合を参照してください。
将来的に、GAUCHE_KEYWORD_DISJOINT
のサポートは無くなる予定です。
今のうちに、現在のデフォルトモードでアプリケーションが走ることを
確認しておくことをお勧めします。
:name
¶名前が :name であるキーワードとして読み込まれます。
obj がキーワードであれば、#t
を返します。
nameの前に:
を付加した名前を持つキーワードを返します。
nameには文字列かシンボルが許されます。
(make-keyword "foo") ⇒ :foo (make-keyword 'foo) ⇒ :foo
キーワード keyword の(先頭の:
を除いた)名前を文字列で返します。
(keyword->string :foo) ⇒ "foo"
キー-値のリストから値を取り出すのに便利な手続きです。 キー-値のリスト kv-list は偶数個の要素を持たなければなりません。 1つ目、3つ目、5つ目、… の要素はキーとして扱われ、 2つ目、4つ目、6つ目、… の要素は、その前の要素をキーとした値と なります。
この手続きは、キーの集合から key を探して、それが見つかれば、 対応する値を返します。 2つ以上のキーにマッチしたら、最左のものとなります。 マッチするキーがない場合、fallback が与えられていればそれを 返し、さもなければエラーを通知します。
kv-list が正しい偶数個の要素を持つリストでない場合は、エラーに なります。
キーワード-値リストの ‘キーワード’ と、key 引数は、実際には
キーワードである必要はありません。いかなる Scheme オブジェクトで
あっても良いです。キーの比較は、eq?
によって行われます。
この手続きは、STk から導入されました。
(get-keyword :y '(:x 1 :y 2 :z 3)) ⇒ 2 (get-keyword 'z '(x 1 y 2 z 3)) ⇒ 3 (get-keyword :t '(:x 1 :y 2 :z 3)) ⇒ #<error> (get-keyword :t '(:x 1 :y 2 :z 3) #f) ⇒ #f
get-keyword
と同様ですが、kv-list が key を
含まない場合にのみ fallback が評価されることだけが違います。
kv-list から key に eq?
であるキーをもつキーと値を
削除します。
delete-keyword
は kv-list を変更しません。しかし、
返されたリストは共通の末尾部分を共有します。
delete-keyword!
は新しくアロケートされることはありません。
そして、破壊的に kv-list を変更する可能性があります。
最初のキーがマッチした場合元のリストは変更されないこともありえますが、
返り値のリストを使わなければいけません。
key にマッチするキーがない場合 kv-list が返ります。
(delete-keyword :y '(:x 1 :y 2 :z 3 :y 4)) ⇒ (:x 1 :z 3)
delete-keyword
やdelete-keyword!
と似ていますが、
keysにオブジェクトのリストを指定できます。
kv-list中のキーがkeysのうちのどれかに一致すれば、
そのキーと続く値がkv-listから取り除かれます。
(delete-keywords '(:x :y) '(:x 1 :y 2 :z 3 :y 4)) ⇒ (:z 3)
• キーワードとシンボルの統合: |
以前のGaucheでは、キーワードはシンボルとは異なる型を持ち、自分自身に評価される
オブジェクトでした。
互換性を保つため、現在のGaucheでは:
で始まるシンボルは自動的に
自分自身に束縛されるようになっています。
表面的にはこの変更はたいした違いをもたらさないでしょう。
プログラム中に表記してあるキーワードはそれ自身に評価されるので、
かつてと同じようにキーワード引数を渡すことができます。
キーワードを変数として使い、例えば(define :key 3)
のように
新たな値に束縛することはできますが、その変更は
そうしているモジュールの中だけに留まります。
(他のモジュールはgauche.keyword
モジュールにある:key
の束縛を
参照するので影響を受けません。)
けれども、違いが現れるいくつかのわかりづらい場合が存在し、 注意していないと古いコードの互換性を壊してしまうかもしれません。 どちらのモードでも動くようにするコードの書き方をこれから説明します。
新しいモードで問題が出て、コードを直すまで以前の動作で使いたければ、
環境変数GAUCHE_KEYWORD_DISJOINT
をセットしてください。
(symbol? :key)
は以前は#f
を返したが、今は#t
を返すキーワードに対してkeyword?
は常に#t
を返しますが、
シンボルかキーワードかで動作を変えるコードでは、キーワードの検査を先にするようにしてください。
;; 0.9.7以前は動作が異なる (cond [(symbol? x) (x-is-symbol)] [(keyword? x) (x-is-keyword)]) ;; どのバージョンでも動く (cond [(keyword? x) (x-is-keyword)] [(symbol? x) (x-is-symbol)])
以前のバージョンでは、util.match
やsyntax-rules
の
パターンにキーワードが現れた場合、それはキーワード自身とのみマッチしました。
現在のバージョンでは、キーワードはシンボルなので、パターン変数として扱われます。
;; 以前のバージョン (match '(a b) [(:key z) (list :key z)] [_ "nope"]) ⇒ "nope" ;; 現在のバージョン ;; :keyは単なるパターン変数となる (match '(a b) [(:key z) (list :key z)] [_ "nope"]) ⇒ (a b)
syntax-rules
でも同じことが起きます。
どのバージョンでも動くコードにするには、マッチさせたいキーワードが リテラルであることを明示してください。
match
では、キーワードをクオートしてリテラルであることを示します。
(match '(a b) [(':key z) (list :key z)] [_ "nope"]) ⇒ "nope"
syntax-rules
では、キーワードをリテラルリストに含めてください。
(syntax-rules (:key) [(_ :key z) (list :key z)]) ;etc.
Gauche 0.9.5から、match
はパターンにクオートされていないキーワードが
現れると警告を発します。
(display :key)
は以前はkey
(コロン無し)を表示しましたが、
現在は:key
を表示します。
key
を表示したい場合は(display (keyword->string :key))
とすれば、
どのバージョンでも同じように動作します。
キーワード(:
で始まるシンボル)はgauche.keyword
モジュール
の中で自分自身に束縛されます。
Gaucheコードはデフォルトでgauche
モジュールを継承し、
それがkeyword
モジュールを継承しているので、
キーワードの束縛は自動的に見えるようになります。
しかしR7RSコードではgauche
モジュールは継承されないので、
:
で始まるシンボルもデフォルトではただのシンボルです。
通常、Gaucheの組み込み機能を使うには(import (gauche base))
としますが、
こうするとキーワードの自分自身への束縛もインポートされるようになっています
(gauche.base
がgauche.keyword
も継承しているからです)。
ただ、Gaucheの手続きとは別にキーワードをR7RSコード中で使いたい場合は
注意してください。自己束縛されているキーワードだけが欲しければ
(import (gauche keyword))
とする必要がありますし、
そうしない場合はキーワードに見えるシンボルでもクオートする必要があります。
(import (scheme base))
:foo ⇒ ERROR: unbound variable: :foo
(import (gauche base))
:foo ⇒ :foo
次の例では、R7RSライブラリfoo
が(gauche base)
から
copy-port
のみをインポートしています。こういった場合、
:size
キーワードをクオートなしで使うには、(gauche keyword)
も
別にインポートしなければなりません。
(あるいは、(gauche base)
からインポートするシンボルのリストに
:size
も明示するか)。
(define-library (foo) (import (scheme base) (only (gauche base) copy-port) (gauche keyword)) (export cat) (begin (define (cat) (copy-port (current-input-port) (current-output-port) :size 4096))))