For Gauche 0.9.5


Next: , Previous: , Up: 組み込みライブラリ   [Contents][Index]

6.8 キーワード

Builtin Class: <keyword>

キーワードは、自動的にクォートされる特別なシンボルのようなものです。 名前で渡す引数(キーワード引数)や、キーワード-値のリストで広く使われて います。

Gaucheにおけるキーワード引数のサポートについては手続きを作るを、 また独自にキーワード-値リストをパーズする方法については let-keywords マクロ(省略可能引数のパージング) も参照して下さい。

CommonLisp とは異なり、Gaucheではキーワードとシンボルを別の型として扱ってきました。 しかしこれはR7RSに違反しています。R7RSでは:で始まる識別子はシンボルとして 読まれるからです。そこで、Gaucheでもキーワードをシンボルのサブタイプとすることにしました。 すなわち、キーワードもシンボルと同様通常の変数として評価されるのですが、 たまたまその値がそれ自身に束縛されているように見えるのです。

この変更は後方互換性を壊す可能性があるので、現在はデフォルトでは有効になっていません。 環境変数GAUCHE_KEYWORD_IS_SYMBOLをセットした状態でgoshを 起動することにより、キーワードがシンボルとして扱われるようになります。

この「キーワードはシンボルのサブタイプ」が近い将来デフォルトの動作になる予定です。 開発者は、GAUCHE_KEYWORD_IS_SYMBOLをセットした状態で ライブラリやアプリケーションが壊れないかどうか確認しておいてください。 互換性を保つ方法については、 キーワードとシンボルの統合を参照してください。

Reader Syntax: :name

名前が name であるキーワードとして読み込まれます。 (先行する ’:’ は、キーワードの名前の一部ではないことに注意してください。)

Function: keyword? obj

obj がキーワードであれば、#t を返します。

Function: make-keyword name

名前が name であるキーワードを返します。nameには 文字列かシンボルが許されます。

(make-keyword "foo")  ⇒ :foo

(make-keyword 'foo)   ⇒ :foo
Function: keyword->string keyword

キーワード keyword の名前を文字列で返します。

(keyword->string :foo) ⇒ "foo"
Function: get-keyword key kv-list :optional fallback

キー-値のリストから値を取り出すのに便利な手続きです。 キー-値のリスト 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
Macro: get-keyword* key kv-list :optional fallback

get-keyword と同様ですが、kv-listkey を 含まない場合にのみ fallback が評価されることだけが違います。

Function: delete-keyword key kv-list
Function: delete-keyword! key kv-list

kv-list から keyeq? であるキーをもつキーと値を 削除します。

delete-keywordkv-list を変更しません。しかし、 返されたリストは共通の末尾部分を共有します。

delete-keyword! は新しくアロケートされることはありません。 そして、破壊的に kv-list を変更する可能性があります。 最初のキーがマッチした場合元のリストは変更されないこともありえますが、 返り値のリストを使わなければいけません。

key にマッチするキーがない場合 kv-list が返ります。

(delete-keyword :y '(:x 1 :y 2 :z 3 :y 4))
 ⇒ (:x 1 :z 3)
Function: delete-keywords keys kv-list
Function: delete-keywords! keys kv-list

delete-keyworddelete-keyword!と似ていますが、 keysにオブジェクトのリストを指定できます。 kv-list中のキーがkeysのうちのどれかに一致すれば、 そのキーと続く値がkv-listから取り除かれます。

(delete-keywords '(:x :y) '(:x 1 :y 2 :z 3 :y 4))
 ⇒ (:z 3)

Previous: , Up: キーワード   [Contents][Index]

6.8.1 キーワードとシンボルの統合

将来のGaucheでは、キーワードは「デフォルトで自分自身に束縛されている」という 性質を持つシンボルとなります。 表面的にはこの変更はたいした違いをもたらさないでしょう。 プログラム中に表記してあるキーワードはそれ自身に評価されるので、 今までどおりキーワード引数を渡すことができます。 今までと違ってキーワードを変数として使い、例えば(define :key 3)のように 新たな値に束縛することはできるようになりますが、その変更は そうしているモジュールの中だけに留まります。そもそも現在のGaucheで キーワードの束縛は許されていないので、この変更は後方互換です。 (キーワードを再定義する時はその効果をわきまえて使ってください)。

けれども、違いが現れるいくつかのわかりづらい場合が存在し、 注意していないと互換性を壊してしまうかもしれません。 現在のGaucheで使えて、さらに将来に渡っても壊れることがないような方法を これから説明します。

ライブラリやアプリケーションがこの変更後も動くかどうかを確かめるには、 環境変数GAUCHE_KEYWORD_IS_SYMBOLをセットして走らせてください。

(symbol? :key)は現在は#fを返すが、将来は#tを返す

キーワードかどうかの判定にはkeyword?を使えますが、 シンボルかキーワードかで動作を変えるコードでは、常にキーワードの検査を先にするように してください。

;; これは壊れる
(cond
  [(symbol? x) (x-is-symbol)]
  [(keyword? x) (x-is-keyword)])

;; これなら大丈夫
(cond
  [(keyword? x) (x-is-keyword)]
  [(symbol? x) (x-is-symbol)])

パターンマッチ中のリテラルキーワード

現在のバージョンでは、util.matchsyntax-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でも同じことが起きます。

どのバージョンでも動くコードにするには、マッチさせたいキーワードが リテラルであることを明示してください。

Gauche 0.9.5から、matchはパターンにクオートされていないキーワードが 現れると警告を発します。

キーワードの表示

(display :key)は今はkeyを表示します(コロン無し)が、 将来は:keyを表示するようになります。

keyを表示したい場合は(display (keyword->string :key))とすれば、 どのバージョンでも同じように動作します。

R7RSコードではクオートするかGaucheのモジュールをインポートする

統合後は、キーワード(:で始まるシンボル)はgauche.keywordモジュール の中で自分自身に束縛されます。

Gaucheコードはデフォルトでgaucheモジュールを継承し、 それがkeywordモジュールを継承しているので、 キーワードの束縛は自動的に見えるようになります。

しかしR7RSコードではgaucheモジュールは継承されないので、 :で始まるシンボルもデフォルトではただのシンボルです。 通常、Gaucheの組み込み機能を使うには(import (gauche base))としますが、 こうするとキーワードの自分自身への束縛もインポートされるようになっています (gauche.basegauche.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キーワードをクオートなしで使うには、(gauhce 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))))

Previous: , Up: キーワード   [Contents][Index]