For Development HEAD DRAFTSearch (procedure/syntax/module):

6.7 シンボル

GaucheはSchemeシンボルを若干拡張しています。

Uninterned symbols

Common Lispのように、内部のテーブルに登録されない 「インターンされない(uninterned)」シンボルを作ることができます。 このシンボルは、他のstring->symbolreadが作るシンボルと 決してeq?にならないことが保証されています。

Schemeの衛生的マクロは名前の衝突を自動的に回避するので、Common Lispほど 出番はありませんが、名前を持つユニークなオブジェクトが欲しい時には便利です。

Keywords

名前がコロン:で始まるシンボルは自動的に、gauche.keywordモジュール内で 自分自身に束縛されます。このモジュールをインポートするか継承すれば、 そういったシンボルをまるで自己評価オブジェクトのように使うことができます。 Gaucheではキーワード引数でこの機能を多用します。


6.7.1 基本的なシンボル

Builtin Class: <symbol>

シンボルを表すクラスです。

Reader Syntax: |name|

[R7RS] シンボルの定義では通常許されないような文字を使った妙な名前のシンボルを表記するのに 使う構文です。16進数エスケープ表記を含めることもできます。

;; 空白を名前に含むシンボル
'|this is a symbol| ⇒ |this is a symbol|

;; Unicodeコードポイントを、バックスラッシュとxからなるエスケープに続けて
;; 書くこともできます。セミコロンで終端します。
'|\x3bb;| ⇒ λ

インタプリタが大文字小文字を区別しないモードで走っている場合は、 大文字を含むシンボルを表記するときにも使えます (大文字小文字の区別参照)。

Function: symbol? obj

[R7RS base] objがシンボルなら#tを返します。

(symbol? 'abc)     ⇒ #t
(symbol? 0)        ⇒ #f
(symbol? 'i)       ⇒ #t
(symbol? '-i)      ⇒ #f
(symbol? '|-i|)    ⇒ #t
Function: symbol=? a b c …

[R7RS base] 全ての引数はシンボルでなければなりません。引数のどの二つの組み合わせを取っても それがeq?である時に限り、#tが返ります。

Function: symbol->string symbol

[R7RS base] symbolの名前を文字列で返します。返される文字列は変更不可です。

(symbol->string 'foo) ⇒ foo
Function: string->symbol string

[R7RS base] 文字列stringを名前に持つシンボルを返します。

(string->symbol "a") ⇒ a
(string->symbol "A") ⇒ A
(string->symbol "weird symbol name") ⇒ |weird symbol name|
Function: symbol-sans-prefix symbol prefix

symbolprefixは共にシンボルでなければなりません。 prefixsymbolの先頭部分にマッチした場合、 symbolからマッチ部分を取り除いた名前を持つシンボルを返します。 マッチしない場合は#fを返します。

(symbol-sans-prefix 'foo:bar 'foo:) ⇒ bar
(symbol-sans-prefix 'foo:bar 'baz:) ⇒ #f
Function: symbol-append interned? objs …
Function: symbol-append objs …

objsの文字列表記をつなげた名前を持つシンボルを返します。

最初の引数が真偽値の場合は、最初の形式と解釈されます。interned?引数は 結果のシンボルがインターンされているかどうかを指定します。

それ以外の引数はそれぞれ次のとおり変換されます:キーワードであれば (先頭の:を含む)名前に、それ以外はx->stringを適用した結果に。 (キーワードを特別扱いするのは、キーワード-シンボル統合の後でも動作が 変わらないようにするためです。詳しくはキーワードとシンボルの統合を 参照。)

これは、Biglooにある同名の手続きの上位互換になっています。Bigloo版は シンボルのみを引数に許し、また結果は常にインターンされます。

(symbol-append 'ab 'cd) ⇒ abcd
(symbol-append 'ab ':c 30) ⇒ ab:c30
(symbol-append #f 'g 100) ⇒ #:g100

6.7.2 インターンされないシンボル

Reader Syntax: #:name

「インターンされていない」シンボルを表記します。インターンされていないシンボルは gensymstring->uninterned-symbolで作ることができます。

インターンされていないシンボルは、良く伝統的なマクロで 変数衝突を避けるために使われます。インターンされていないシンボルは 内部のシンボルのテーブルに登録されないため、同じ名前のシンボルでも eq?になりません。

(eq? '#:foo '#:foo) ⇒ #f
(eq? '#:foo 'foo) ⇒ #f

インターンされていないシンボルが含まれるS式を、 シンボルの同一性を保って表示するには、 write-sharedを使います。

(write-shared (let1 s '#:foo (list s s)))
  ⇒ prints (#0=#:foo #0#)

(write-shared (let ((s '#:foo) (t '#:foo)) (list s t s t)))
  ⇒ prints (#0=#:foo #1=#:foo #0# #1#)
Function: symbol-interned? symbol

[SRFI-258] シンボルsymbolがインターンされていれば#tを、 そうでなければ#fを返します。シンボルでないものが渡された場合はエラーとなります。

これはSRFI-258に含まれています(srfi.258 - インターンされないシンボル(SRFI)参照)。

Function: string->uninterned-symbol string

[SRFI-258] string->symbolと似ていますが、作られたシンボルはインターンされません。

(string->uninterned-symbol "a") ⇒ #:a

これはSRFI-258に含まれています(srfi.258 - インターンされないシンボル(SRFI)参照)。

Function: gensym :optional prefix

インターンされてない、新しいシンボルを作って返します。 返されるシンボルは、他のシンボルとは決してeq?にならないことが保証されます。 prefixが与えられた場合は、それは文字列でなければならず、 それが作られるシンボルのプレフィクスに使われます。これは主としてデバッグを 容易にするためのものです。

これはSRFI-258のgenerate-uninterned-symbolと似ています (インターンされないシンボル参照)。


6.7.3 キーワード

Builtin Class: <keyword>

キーワードは、自動的に自分自身に束縛されるシンボルのサブタイプです。 名前つき引数(キーワード引数)や、キーワード-値のリストで広く使われて います。

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

註: キーワードはかつてはシンボルと独立した型でした。互換性のために、 0.9.15までは、環境変数によって以前の振る舞いに切り替えるモードがありましたが、 そのモードはサポートされなくなりました。 以前の振る舞いに依存しているコードがあればキーワードとシンボルの統合を 参考にアップデートしてください。

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)

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

以前のGaucheでは、キーワードはシンボルとは異なる型を持ち、自分自身に評価される オブジェクトでした。 互換性を保つため、現在のGaucheでは:で始まるシンボルは自動的に (gauche.keywordモジュール内に)自分自身に束縛されるようになっています。

gaucheモジュールはgauche.keywordモジュールを継承しているので、 キーワードはあたかも自己評価されるオブジェクトのように見えます。 これにより、古いGaucheコードもほぼ変更なしで動作します。 ただ、いくつか注意すべき点があります。

(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.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でも同じことが起きます。

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

キーワードの表示

(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キーワードをクオートなしで使うには、(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))))


For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT