For Gauche 0.9.5


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

6.22 入出力


Next: , Previous: , Up: 入出力   [Contents][Index]

6.22.1 ポート

Builtin Class: <port>

Portは、Schemeにおいて抽象化された入出力のインタフェースを提供します。 Gaucheはportにいくつかの拡張を行い、いろいろなアプリケーションに対応できるようにしました。

テキストとバイナリI/O

R7RSはテキストポートとバイナリポートを定義しています。 Gaucheでは、ほとんどのポートはテキストI/OとバイナリI/Oを混ぜて使えます。 概念的には、異なる型のオブジェクトのソース/シンクは別物と考える方が綺麗ですし、 ひとつのポートでテキストI/OとバイナリI/Oを混在して使うことは滅多にありません。

しかし現実には、ポートを型の無いデータの集まりにつながったものとして、 データをどう解釈するかは後から決めたい、という場合があります。 例えば標準入出力です。Unix的な環境では、あらかじめオープンされている標準入出力 に対してテキストI/Oを行うかバイナリI/Oを行うかはプログラムに任されています。 R7RSでは、current-input-port等の初期値はテキストポートであると 規定しています。Gaucheではどちらにも使うことができます。

変換

ポートはまた、データストリームを変換するのにも使えます。例えばgauche.charconv モジュールでは、文字コード間の変換を行うポートを提供しています (詳しくは文字コード変換を参照)。

追加機能

また、特殊な機能を実現するポートもあります。 コーディング認識ポート(コーディング認識ポート参照)は ファイル中の特殊なコメントを認識して、そのファイルがどの文字エンコーディング で書かれているかを検出します。 仮想ポート(仮想ポート参照)はSchemeでふるまいをプログラムできる ポートを提供します。


Next: , Previous: , Up: 入出力   [Contents][Index]

6.22.2 ポートとスレッド

GaucheがスレッドサポートをONにしてコンパイルされている場合、 組み込みのポート操作関数はポートをロックして、 複数のスレッドからの同一のポートへのアクセスがポートの内部状態を壊さないように しています。 (SRFI-18によって要求されている動作です)。 ここで「組み込みのポート操作関数」はGaucheにより提供される、 ポートを引数に取り何らかのI/O動作や問い合わせを行う手続きで、 read/writeread-char/write-charport->string等を含みます。 但し、call-with-*with-*系関数は、 与えられた手続きを呼ぶ際にはポートをロックしません。 その手続きが別のスレッドにポートを渡すかもしれず、Gaucheにはそれを知ることが できないからです。

従って、マルチスレッド環境でポートへのアクセス競合により ポートの内部状態を壊してしまうんじゃないか、などとあまり神経質に なる必要はありません。但し、このロック機構はあくまで予想外の アクセス競合によってポートがおかしな状態になってしまうことを 防ぐための安全ネットであって、一般的な排他制御機構として使われる ことは想定していないのに注意して下さい。このロックの実装は、 ポートへのアクセス競合は例外的な場合のみであると仮定し、 通常のアクセスにおけるオーバヘッドを避けるために、スピンロックを 使用します。もし、意図的にポートアクセスが競合するようなコードを書く場合は、 明示的に排他制御をしてください。

Function: with-port-locking port thunk

portをロックし、thunkを実行します。 ロックはthunkのダイナミックエクステントの期間有効です。

portがロックされている期間での組み込みのポートアクセス関数の 呼び出しは排他制御をバイパスするため、性能向上が見込まれます。

ロックの有効期間はthunkのダイナミックエクステントなので、 thunk内からwith-port-lockingの外で捕捉された 継続を呼んだ場合、ロックは解放されます。その後、thunk内で 捕捉された継続が呼ばれた場合、再びロックが獲得されます。

with-port-lockingはネスト可能です。ロックは最も外側の with-port-lockingの期間中有効となります。

この手続きはポート組込みのロック機構を利用します。つまり、ポートアクセスが 競合した場合はbusy waitになるということです。この手続きはあくまで 頻繁なロックによるオーバヘッドを回避するためのものです。 もし本当に競合が予測される場合は明示的に排他制御を行ってください。


Next: , Previous: , Up: 入出力   [Contents][Index]

6.22.3 ポート共通の操作

Function: port? obj
Function: input-port? obj
Function: output-port? obj

[R7RS] obj がそれぞれポート、入力ポート、出力ポートなら真を返します。 port?はR5RSの"Standard Procedures"の項には 載っていませんが、"Disjointness of Types"の項に挙げられています。

Function: port-closed? port

objがポートであり、既に閉じられていた場合に真を返します。 一度閉じたポートは再び開くことはできません。

Parameter: current-input-port
Parameter: current-output-port
Parameter: current-error-port

[R7RS] 現在の入力ポート、出力ポート、エラー出力ポートをそれぞれ返します。

R7RSではこれらのポートの初期値はテキストポートであると規定されています。 Gaucheでは、これらのポートの初期値はテキスト入出力もバイナリ入出力も扱えます。

現在のポートの値はparameterizeを使って一時的に変更できます (パラメータ参照)。もっとも、典型的な場合には より簡単なwith-output-to-stringwith-input-from-fileなどの 手続きが使えるでしょう。

(use gauche.parameter)
(let1 os (open-output-string)
  (parameterize ((current-output-port os))
    (display "foo"))
  (get-output-string os))
 ⇒ "foo"
Parameter: standard-input-port
Parameter: standard-output-port
Parameter: standard-error-port

プログラム開始時点の標準入出力ポートを返します。これらの値が current-input-portcurrent-output-portcurrent-error-portのデフォルトとなります。

これらの手続きの値もparameterizeで変えることができますが、 (1) current-*-portはプログラム実行前に初期化されるので、 プログラム中でstandard-*-portを変更しても影響は及ばない、 (2) これらの手続きの値の変更はScheme世界だけのことで、低レベルライブラリが 参照しているシステムのstdioファイルディスクリプタは変更されない、 という点に注意してください。

Function: with-input-from-port port thunk
Function: with-output-to-port port thunk
Function: with-error-to-port port thunk

それぞれ入力、出力、エラーポートをportにセットした状態でthunkを呼び出します。 portthunk実行後にも閉じられないことに注意してください。

Function: with-ports iport oport eport thunk

上の3つの動作を同時に行う手続きです。 入力、出力、エラーの各ポートをそれぞれiport, oport, eportに セットしてthunkを呼び出します。変更する必要がないポートの引数には #fを渡すことができます。

portthunk実行後にも閉じられないことに注意してください (最近のScheme標準は良く似た名前の手続きcall-with-portを追加しましたが、 生憎そちらはポートを閉じる仕様になっています。call-with-portについては 下で説明します。)

Function: close-port port
Function: close-input-port port
Function: close-output-port port

[R7RS] ポートを閉じます。close-portは入力ポートも出力ポートも閉じられますが、 close-input-portclose-output-portはそれぞれ対応するポートのみに 使え、異なる種類のポートが渡されたらエラーを通知します。

理屈の上では、close-portだけあれば十分です。3つ手続きがあるのは歴史的理由です。 R5RSにはclose-input-port and close-output-portだけがありました。 R6RSとR7RSは3つ全てをサポートしています。

Function: call-with-port port proc

[R7RS] procを、portを引数として呼び出します。procからリターンするか、 エラーが投げられた場合はportがクロースざれます。 procが返す値がそのままcall-with-portの返り値となります。

Function: port-type port

portのタイプを、シンボルfilestringprocの いずれかで返します。

Function: port-name port

portの名前を返します。ポートがファイルに関連付けられている場合は、ポートの名前は ファイル名です。そうでない場合、ポートを説明する文字列が返されます。

Function: port-buffering port
Function: (setter port-buffering) port buffering-mode

ファイルポート((port-type port)fileを返すもの) に対して、そのバッファリングモードを読みだし、もしくは変更します。 入力ポートではバッファリングモードは :full:modest:noneのいずれかです。 出力ポートでは :full:line:noneのいずれかです。 バッファリングモードの詳細な説明は、ファイルポート を参照してください。

port-bufferingがファイルポート以外のポートに対して呼ばれた場合は #fを返します。port-bufferingのsetterが ファイルポート以外のポートに対して呼ばれた場合はエラーとなります。

Function: port-current-line port

portの現在の行番号を返します。行番号は、ファイルに関連付けられたポートで かつシーケンシャルなキャラクタI/Oを行っている場合のみ有効です。それ以外の場合は -1を返します。

Function: port-file-number port

portがファイルに関連付けられている場合、そのファイルディスクリプタ番号を 返します。それ以外の場合は#fを返します。

Function: port-seek port offset :optional whence

portがランダムアクセス可能なポートの場合、 この手続きはportのread/writeポインタをoffsetwhenceの値によって 設定し、新たなread/writeポインタの値(データの先頭からのバイトオフセット)を 返します。portがランダムアクセス可能でない場合は#fが返されます。 現在のバージョンでは、ファイルポートおよび入力文字列ポートがランダムアクセス可能です。 出力文字列ポートは現在のポインタの値を問い合わせる動作だけが可能です。

ポートのポインタはバイト数で表現され、文字数とは異なることに注意して下さい。

portが出力ファイルポートの場合は、データの終端を超えた位置までseek することが可能です。その場合の動作はPOSIXのlseek(2)に準じます。 入力ファイルポートや入力文字列ポートではデータの終端以降にseekすることはできません。

whence引数は、offsetの基準を指定する小さな整数です。 以下の定数が定義されています。

SEEK_SET

offsetはデータ先頭からのバイト数を指定します。 whenceが省略された場合のデフォルトの動作です。

SEEK_CUR

offsetは現在のread/writeポインタからの相対バイト数を指定します。 offsetが0であれば、ポインタを動かさずに現在のポート位置を知ることができます。

SEEK_END

offsetはデータの終端からの相対バイト数を指定します。

Function: port-tell port

portの現在のread/writeポインタの値をバイト数で返します。 portがランダムアクセス可能でない場合は#fが返されます。 これは以下の呼び出しと等価です。

(port-seek port 0 SEEK_CUR)

名前に関するメモ: port-seekは他の処理系で seekfile-positioninput-port-position/ output-port-position等と呼ばれています。 port-telltellftellset-file-position!等と 呼ばれています。いくつかの処理系はport-positionという手続きを 持っていますが、port-seekとは別の機能を実現しています。 file-positionはCommonLisp由来の名前ですが、 fileポート以外のものも扱うため採用しませんでした。 また、seektellはPOSIXの名前由来であり、 Gaucheの名前付け規則を使ってsys-seeksys-tellとしても よさそうですが、portの操作はシステムコールレベルよりも抽象度が高いため これも採用しませんでした。結局、新しい名前を採用することにしました。

Function: copy-port src dst :key (unit 0) (size #f)

srcからEOFまでデータを読みだし、dstへ書き出します。

キーワード引数unitは0以上の整数か、シンボルbyteもしくはchar でなければなりません。これはデータをコピーする単位を指定します。 整数ならば、その大きさ(0の場合はシステム規定の大きさ)のバッファが確保され、 ブロックI/Oを使って転送が行われます。通常のファイルをコピーする場合などはこれが 速いでしょう。もしunitがシンボルbyteであれば、バイト毎 に読みだし/書き込みが行われます。unitがシンボルcharであれば、 キャラクタ毎に読みだし/書き込みが行われます。

キーワード引数sizeに非負の整数が与えられた場合、それはコピーされるデータの 最大量を指定します。unitがシンボルcharの場合はsizeは コピーされる文字数を、そうでない場合はバイト数を指定します。

unitがシンボルcharの場合はコピーされた文字数を返し、 そうでない場合はコピーされたバイト数を返します。


Next: , Previous: , Up: 入出力   [Contents][Index]

6.22.4 ファイルポート

Function: open-input-file filename :key if-does-not-exist buffering element-type encoding conversion-buffer-size
Function: open-output-file filename :key if-does-not-exist if-exists buffering element-type encoding conversion-buffer-size

[R7RS+] ファイルfilenameを入力または出力用にオープンし、 入力ポートまたは出力ポートを作成して返します。

キーワード引数により、動作を細かく指定できます。

:if-exists

このキーワード引数はopen-output-fileのみに指定でき、 filenameが既に存在した場合の動作を指定します。次の値のいずれかを与えることができます。

:supersede

既存のファイルが長さ0に縮められます。これが既定の動作です。

:append

既存のファイルにこれから書き出す内容が追加されます。

:overwrite

既存のファイルにこれから書き出す内容が上書きされます。 書き出されるデータが既存のファイルのデータよりも短い場合、 残りの部分はそのまま残されます。

:error

エラーが報告されます。

#f

何もせず、#fを返します。

:if-does-not-exist

このキーワード引数はfilenameが存在しない場合の動作を指定します。

:error

エラーを報告します。これがopen-input-fileの既定の動作です。

:create

ファイルが作成されます。これがopen-output-fileの既定の動作です。 ファイルの存在のチェックと作成はアトミックに行われます。 このオプションに加え、if-existsオプションに:error#fを 指定することで、排他的にファイルを作成することができます。 open-input-fileに対してはこの値を指定することはできません。

#f

何もせず、#fを返します。

:buffering

この引数はバッファリングモードを指定します。以下の値が設定できます。 ポートのバッファリングモードは手続きport-buffering (ポート共通の操作参照)によって 読みだし/変更可能です。

:full

出来る限りデータをバッファリングします。これがデフォルトのモードです。

:none

バッファリングを行いません。出力ポートにデータが書き出されるか、 入力ポートからデータが読み込まれる度に、下位にあるシステムコールが呼ばれます。 プロセスの標準エラーポートはこのモードでオープンされています。

:line

このモードは出力ポートにのみ有効です。書き出されたデータはバッファに 貯められますが、改行文字が書かれたらフラッシュされます。 このモードは対話的な出力ポートなどに便利です。 プロセスの標準出力ポートはこのモードでオープンされています。 (これは、Cのstdioライブラリの「ラインバッファリング」とちょっと違うことに 注意してください。stdioでは同じファイルディスクリプタから入力が行われる時も バッファはフラッシュされますが、Gaucheではそうはなりません)。

:modest

このモードは入力ポートにのみ有効です。ほとんど:fullバッファリングモードと 同じですが、read-uvectorはポートに要求されたデータより少ないデータしか 無かった場合、要求された量がたまるまで待つのではなく、今あるデータだけを 返します(:fullの場合はread-uvectorはすべてのデータが到着するまで 待ちます)。このモードはポートがパイプやネットワークに接続されている場合に 便利です。

:element-type

この引数はファイルのタイプを指定します。

:character

ファイルはキャラクタモード(テキストモード)でオープンされます。

:binary

ファイルはバイナリモードでオープンされます。

現在のバージョンでは、この引数は無視され、全てのファイルはバイナリモードで オープンされます。いずれにせよUnixプラットフォームでは違いはありません。

:encoding

この引数はファイルの文字エンコーディングを指定します。引数は文字列かシンボルで、 文字エンコーディングスキーム(CES)の名前を渡します。

open-input-fileでは、ここにワイルドカードCES (例: *jp) を 渡して、入力ファイルのエンコーディングを推測させることもできます (文字エンコーディングの自動判定参照)。 また、ここに#tを渡すと、入力ポートはCoding aware portでラップされます (コーディング認識ポート参照)。入力ファイルがエンコーディング指定の マジックコメントを持っていることが期待できる場合に便利です。

この引数が与えられた場合、Gaucheは自動的にgauche.charconvモジュールを ロードし、ポートの入出力時に文字コード変換を行います。 CESについて詳しくはサポートされる文字エンコーディングを参照してください。

:conversion-buffer-size

この引数は、文字エンコーディング変換に使うバッファサイズを指定するために encoding引数と共に使うことができます。渡された値はそのまま 文字コード変換ポートのコンストラクタのbuffer-size引数に渡されます (変換ポート参照)。

この引数を指定する必要は滅多にありませんが、入力ファイルの文字エンコーディングを 推測しなければならない場合、大きめのバッファサイズの方が精度が上がります。 推測ルーチンがより多くのデータを見て文字エンコーディングを決定できるからです。

if-existsif-does-not-existフラグの組合せにより、 色々な動作を実現できます。

(open-output-file "foo" :if-exists :error)
 ⇒ ;"foo"を排他的にオープンするかエラーを報告する

(open-output-file "foo" :if-exists #f)
 ⇒ ;"foo"を排他的にオープンするか#fを返す

(open-output-file "foo" :if-exists :append
                        :if-does-not-exist :error)
 ⇒ ;"foo"が既に存在する場合に限り、それを追加モードでオープン

ファイルをオープンせずにその存在をチェックするには、 sys-accessfile-exists?を使って下さい (ファイルの状態参照)。

移植性に関する註:Schemeシステムによっては、filenameのところに シェルコマンドを指定して、サブプロセスの標準入出力と通信できるようにするものが あります。他のスクリプティング言語(例:Perl)にも同様の機能があります。 Gaucheでは、open-input-fileopen-output-fileは あくまでファイル (OSがファイルとして扱うもの) のみに対して使えます。 サブプロセスと通信するためには、「プロセスポート」という機能が提供されています。 Process portsを参照して下さい。

Function: call-with-input-file string proc :key if-does-not-exist buffering element-type encoding conversion-buffer-size
Function: call-with-output-file string proc :key if-does-not-exist if-exists buffering element-type encoding conversion-buffer-size

[R7RS+] stringで示されるファイルを入力または出力用にオープンし、 作成されたポートを引数として手続きprocを呼び出します。 procが正常終了するか、proc内で捕捉されないエラーが起きた場合に ファイルはクローズされます。

キーワード引数は open-input-file及びopen-output-fileのものと同じ意味を持ちます。 if-existsif-does-not-exist#fを指定した場合、 ファイルがオープンされなかった場合はprocにポートではなく#fが渡される ことに注意して下さい。

procが返す値を返します。

Function: with-input-from-file string thunk :key if-does-not-exist buffering element-type encoding conversion-buffer-size
Function: with-output-to-file string thunk :key if-does-not-exist if-exists buffering element-type encoding conversion-buffer-size

[R7RS] stringで示されるファイルを入力または出力用にオープンし、オープンされた ポートを現在の入力または出力ポートに設定して、thunkを呼び出します。 thunkが戻るか、thunk内で捕捉されないエラーが生じた際にファイルは閉じられます。

thunkが返す値を返します。

キーワード引数は open-input-file及びopen-output-fileのものと同じ意味を持ちます。 但しif-existsif-does-not-exist#fが指定され、 ファイルがオープンできなかった場合は、thunkは呼ばれずに 直ちに#fが返されます。

ポートを閉じるセマンティクスについて: R7RSはcall-with-port等の説明において、次のように述べています。 「procが戻って来なかった場合、今後ポートが読み書きに一切使われないことが 証明できない限りは、ポートは自動的には閉じられない」。

Gaucheの実装は若干この条件には反しています。捕捉されないエラーがprocから 発せられたというだけでは、そのポートが今後一切使われないかどうかはわかりません。 しかし実際には、そのようなエラーが発せられた後でポートに対して意味のある操作をするのは 非現実的です。ポートがどのような状態にあるかわからないわけですから。 現実的なプログラムでは、ポートに対して意味のある操作をしつづけたいのなら、 procの中で明示的にエラーをハンドルすべきでしょう。

call-with-input-fileの外で捕捉された継続をproc内で呼んだ場合には ポートは閉じられないことに注意して下さい。後でprocへと制御が戻ってくるかも しれないからです (コルーチン等)。また、 低レベルの例外メカニズム(例外の処理 参照)を利用した場合、エラー時にポートを閉じるのはプログラマの責任になります。

Function: open-input-fd-port fd :key buffering name owner?
Function: open-output-fd-port fd :key buffering name owner?

与えられたファイルディスクリプタにアクセスする入力または出力ポートを 作成して返します。bufferingopen-input-file の項で 説明されたポートのバッファリングモードを指定します。デフォルトは:fullです。 nameport-nameによって返されるポートの名前を指定します。 owner? は、このポートを閉じた時にfdもクローズすべきかどうかを 指定するブーリアン値です。

Function: port-fd-dup! toport fromport

システムのdup2(2)のインタフェースです。 アトミックにtoportのファイルディスクリプタをクローズし、fromportの ファイルディスクリプタを複製したものをtoportに設定します。 toportfromportはいずれもファイルポートでなければなりません。

ファイルディスクリプタが「複製」されると、ふたつのディスクリプタ番号が異なっていても それらはシステムのオープンファイルテーブルの同じエントリを指します。 例えば、現在の(システムレベルでの)ファイル上の読み書き位置は共有されます。 port-fd-dup!の後で、port-seekfromportに 対して呼び出せば、その変更はtoportの読み書き位置にも影響を与えるでしょうし、 その逆もまたあります。ただし、共有されるのはシステムレベルの情報のみで、 toportfromportがバッファリングされている場合、バッファの内容は 共有されません。

この手続きは、主にファイルディスクリプタを明示的に制御する必要のあるプログラム のために用意されています。例えばデーモンプロセスがその入出力を/dev/nullなどの 無難なデバイスに切り替えたり、シェルプロセスが子プロセスをexecする前に そのファイルディスクリプタをセットアップしたりするような場合です。


Next: , Previous: , Up: 入出力   [Contents][Index]

6.22.5 文字列ポート

文字列ポートは、メモリ上のデータと関連付けられたポートです。

Function: open-input-string string

[R7RS][SRFI-6] stringを内容とする入力文字列ポートを作って返します。 文字列に逐次的にアクセスする場合、インデックスをインクリメントしながら string-refを呼び出すより効率の良い方法です。

(define p (open-input-string "文字 列"))
(read p) ⇒ 文字
(read-char p) ⇒ #\space
(read-char p) ⇒ #\列
(read-char p) ⇒ #<eof>
(read-char p) ⇒ #<eof>
Function: get-remaining-input-string port

portは入力文字列ポートでなければなりません。 入力ポートに残っている文字列を返します。 portの内部ポインタは動かされないので、portに対するreadは 影響を受けません。portが既にEOFに達していた場合は、空文字列が返されます。

(define p (open-input-string "abc\ndef"))
(read-line p)                  ⇒ "abc"
(get-remaining-input-string p) ⇒ "def"
(read-char p)                  ⇒ #\d
(read-line p)                  ⇒ "ef"
(get-remaining-input-string p) ⇒ ""
Function: open-output-string

[R7RS][SRFI-6] 出力文字列ポートを作成して返します。このポートに書き出された文字列は 内部のバッファにたくわえられ、get-output-string で取り出すことが できます。 これは、順番に文字列を構成する方法として、あらかじめ文字列をアロケートして string-set!で埋めて行くよりもずっと効率の良い方法です。

Function: get-output-string port

[R7RS][SRFI-6] 出力文字列ポートportを取り、それまでそのポートに蓄積された 文字列を返します。バイトデータがそのポートに書き出されていた場合、 この手続きはまず内部バッファをスキャンし、結果が完全な文字列で表現できるかどうかを 調べます。もし表現できなければ、不完全な文字列が返されます。

これはportの操作には影響をあたえません。get-ouptut-stringを 呼んだ後でも、portに内容を蓄積しつづけることができます。

Function: call-with-input-string string proc
Function: call-with-output-string proc
Function: with-input-from-string string thunk
Function: with-output-to-string thunk

これらのユーティリティ関数は次に定義されるような動作をします。 インタフェースはファイルポートを扱う類似の関数と揃えてあります。

(define (call-with-output-string proc)
  (let ((out (open-output-string)))
    (proc out)
    (get-output-string out)))

(define (call-with-input-string str proc)
  (let ((in (open-input-string str)))
    (proc in)))

(define (with-output-to-string thunk)
  (let ((out (open-output-string)))
    (with-output-to-port out thunk)
    (get-output-string out)))

(define (with-input-from-string str thunk)
  (with-input-from-port (open-input-string str) thunk))
Function: call-with-string-io str proc
Function: with-string-io str thunk
(define (call-with-string-io str proc)
  (let ((out (open-output-string))
        (in  (open-input-string str)))
    (proc in out)
    (get-output-string out)))

(define (with-string-io str thunk)
  (with-output-to-string
    (lambda ()
      (with-input-from-string str
        thunk))))
Function: write-to-string obj :optional writer
Function: read-from-string string :optional start end

文字列ポートを使う定型句をユーティリティ関数にしました。

(write-to-string obj writer)
  ≡
  (with-output-to-string (lambda () (writer obj)))

(read-from-string string)
  ≡
  (with-input-from-string string read)

writerの既定値はwriteです。start, endは 省略されればそれぞれ0と文字列の長さになります。

移植性への註:Common Lispに同名の関数があります。必須引数の動作は同じですが、 省略可能な引数は異なります。 STkにはread-from-stringがありますが、省略可能な引数は取りません。


Next: , Previous: , Up: 入出力   [Contents][Index]

6.22.6 コーディング認識ポート

コーディング認識ポートは特殊な手続的入力ポートで、loadが プログラムソースコードを読む際に使われています。このポートは ;; -*- coding: utf-8 -*-のような、プログラムソースの 文字エンコーディングを指定する特殊なコメントを認識し、適切な 文字エンコーディング変換を行います。 特殊なコメントでソースの文字エンコーディングを指定することについては、 マルチバイトスクリプトを参照して下さい。

Function: open-coding-aware-port iport

入力ポートを引数としてとりコーディング認識入力ポートを返します。 基本的には iport からの入力データをリーダにわたしているだけです。 しかし、iport からの入力データの最初の2行以内に、特別な呪文コメント が現れた場合、コーディング認識ポートは、その後に読み込まれるデータについて 必要な文字エンコーディング変換を行います。

引数として渡されたポート、iport は生成されたコーディング認識 ポートによって所有されます。つまり、コーディング認識ポートがクローズ されると、iport もクローズされます。iport から読み込まれた 内容はコーディング認識ポート内でバッファリングさます、したがって、 別のコードで iport から読み出しを行うべきではありません。

デフォルトでは、Gauche の load はプログラムソースを読むのに コーディング認識ポートを使います。したがって、文字エンコーディングを 示す特別な呪文コメントは、Gauche のソースプログラムでは有効になります (Schemeファイルのロード参照)。ただし、この機構自身は load とは 独立しており、このポートを別の目的で利用できます。特にコーディングの 呪文コメントがある Scheme のソースプログラムを処理する関数を書くときに 便利です。


Next: , Previous: , Up: 入出力   [Contents][Index]

6.22.7 入力

入力に関する手続きで、省略可能な引数iportは入力ポートでなければなりません。 省略された場合が現在の入力ポートが使われます。


Next: , Previous: , Up: 入力   [Contents][Index]

6.22.7.1 データの読み込み

Function: read :optional iport

[R7RS] iportからS式をひとつ読み込んで返します。 GaucheはR7RSに定義されている構文要素に加え、字句構造に 定義されている拡張構文要素を認識します。

iportが既にEOFに達していた場合は、EOFオブジェクトが返されます。

この手続きはS式を構成する最後の文字までを読み、その後の文字はポートに 残します。これは、S式に続く空白文字も読み込むCommonLispのreadの 振る舞いとは異なります。

Function: read-with-shared-structure :optional iport
Function: read/ss :optional iport

[SRFI-38] これらの手続きは、SRFI-38 で定義されていて、共有構造を表す記法 (#n=, #n#)を認識できます。Gauche の組み込み read は この SRFI-38 の記法を認識します。それゆえ、これらの手続きは、read と同じで、SRFI-38 との互換性のために用意されています。

Function: read-char :optional iport

[R7RS] iportから1文字読み込んで返します。 iportが既にEOFに達していた場合はeofオブジェクトを返します。 iportにあるバイトストリームが正しい文字を構成しない場合、 ふるまいは未定義です。(将来はポート側に、不正な文字に対する対応を決める オプションを設ける予定です)。

Function: peek-char :optional iport

[R7RS] iportから1文字読み込んで返します。文字はそのままiportに留まります。 iportが既にEOFに達していた場合はeofオブジェクトを返します。 iportにあるバイトストリームが正しい文字を構成しない場合、 ふるまいは未定義です。(将来はポート側に、不正な文字に対する対応を決める オプションを設ける予定です)。

Function: read-byte :optional iport

入力ポートiportから1バイト読み込み、0から255までの整数値として返します。 iportが既にEOFに達していた場合はeofオブジェクトを返します。

R7RSではread-u8と呼ばれています。

Function: peek-byte :optional iport

入力ポートiportの先頭の1バイトを見て、それを0から255までの整数値として返します。 iportが既にEOFに達していた場合はeofオブジェクトを返します。

R7RSではpeek-u8と呼ばれています。

Function: read-line :optional iport allow-byte-string?

[R7RS+] 入力ポートから、行末もしくはEOFまで読み込んで文字列として返します。 よく使われる行末 (LF only, CRLF, and CR only) を認識します。 戻り値にはこれらの行末文字は含まれません。 iportが既にEOFに達していた場合はeofオブジェクトを返します。

iportから、内部文字エンコーディングでは文字を構成し得ないバイトシーケンスが 読まれた場合、デフォルトではread-lineはエラーを通知します。 しかし、省略可能な引数allow-byte-string?に真の値が与えられた場合は、 read-lineはエラーを通知せず、かわりにバイト文字列 (不完全な文字列) を 返します。この動作は、特に文字エンコーディングが不明なソースから読み込む際に 便利です。例えばXMLドキュメントを読み込む際、最初の行のcharsetパラメータを チェックしてから適切な文字エンコーディング変換ポートを使うといった用途などです。 この動作はGauche独自の拡張です。

Function: read-string nchars :optional iport

[R7RS] nchars文字を読み込み、もしくはそれ以前にEOFに達したら読めただけの文字を 使って文字列を作って返します。もし入力が既にEOFに達していた場合は EOFを返します。

Function: read-block nbytes :optional iport

この手続きは非推奨になりました。read-uvectorを使ってください (ユニフォームベクタのブロック入出力参照)。

nbytesバイトのデータをiportから読み込み、 不完全な文字列として返します。iportに十分なデータが無い場合、 返される文字列はnbytesより短いかもしれません。 nbytesが0の場合は、常に空文字列が返されます。

iportが既にEOFに達していた場合はEOFオブジェクトが返されます。

iportがファイルポートだった場合、read-blockは ポートのバッファリングモードによってふるまいが異なります (バッファリングモードの詳細についてはファイルポートを参照して下さい)。

データブロックをポートに書き出すには、データが文字列で表現されている 場合は単純にdisplayが使えます。データがuniform vectorで表現されている 場合はgauche.uvectorモジュールのwrite-uvectorが 使えます (ユニフォームベクタのブロック入出力参照)。

Function: eof-object

[R7RS] EOFオブジェクトを返します。

Function: eof-object? obj

[R7RS] objがEOFオブジェクトなら#tを返します。

Function: char-ready? :optional port

[R7RS] portから文字が読み出せる状態ならば#tを返します。

今のところ、この手続きはportから少なくとも1バイト読み出せる状態なら#t を返します。そのバイトがマルチバイト文字を構成する場合、char-ready?を返した ポートから文字全てを読み込もうとすると、ブロックする可能性があります。 (通常の使用状況ではそのようなことは起きないでしょうが、理論的には起こり得ます。 慎重を期したい場合はread-uvectorでバイトシーケンスとして読み込んだ後、 入力文字列ポート等を使って文字毎に読むようにして下さい。)

Function: byte-ready? :optional port

portから1バイトをすぐに読み込める状態なら#tを返します。

R7RSではこの手続きはu8-ready?と呼ばれています。


Next: , Previous: , Up: 入力   [Contents][Index]

6.22.7.2 リーダー字句モード

Parameter: reader-lexical-mode

現在のリーダ字句モードを表すパラメータです。 このパラメータの値を変えることにより、旧来のGaucheとR7RSで非互換となる コーナーケースの字句構文についての解釈を変更できます。

一般的には、このパラメータを直接変える必要のある場合は少ないでしょう。 字句構文は読み込み時に問題となりますが、パラメータの変更は実行時に起こります。 いつ、何が起きるかを正確に把握しているのでない限り、意図したとおりの効果は 得られないかもしれません。

hash-bang指示子 #!gauche-legacy および #!r7rs は 間接的にこのパラメータに影響を与えます。#!gauche-legacyは リーダモードをlegacyに、#!r7rsstrict-r7に 変更します。

コマンドライン引数の-fwarn-legacyはデフォルトのリーダモードを warn-legacyにセットします。

load中にこのパラメータを変更した場合、その効果はloadの期間中に 留まります。そのloadが終了した時点で、 load開始時のリーダモードが復元されます。

このパラメータは値として次のシンボルのうちいずれかを取ります。

permissive

これがデフォルトのモードです。二つの構文の、ほどほどの妥協点を見つけようとします。

文字列リテラル中の16進数エスケープシーケンスは、まず R7RSの字句構文で解釈されます。もしそれがR7RSの16進数エスケープシーケンスの 構文に沿っていなかった場合は、旧来のGaucheの構文で解釈されます。 例えば、"\x30;a" は、セミコロンがR7RSのエスケープシーケンスの終端と みなされ、"0a" と読まれます。一方で "\x30a""0a" と 読まれます。終端のセミコロンが無く、有効なR7RSの構文でないため、 旧来のGaucheのエスケープシーケンスとして2桁固定で解釈されるからです。 このモードでは、新たなコードでR7RSエスケープシーケンスを利用できるうえ、 ほとんどの既存のGaucheコードはそのまま走ります。 しかし、もし既存のGaucheコードで、たまたま2桁の16進数エスケープの直後に セミコロンがあった場合、それはR7RSとして読まれ、非互換性が生じます。

コロンで始まる識別子は従来通りキーワードとして読まれます。厳密にR7RSと同じ 振る舞いにする、つまりシンボルとして読ませるには、縦棒でエスケープしてください。 (例: |:foo|)。この非互換性は、将来のGaucheでキーワードがシンボルの サブタイプとなった時に解消されます。

strict-r7

厳密にR7RS互換なモード。 リーダが、hash-bang指示子#!r7rsに出会うと、ファイルの残りの部分は このモードで読まれます。

このモードでは、Gaucheの拡張字句構文はエラーとなります。 コロンで始まる識別子はシンボルとして読まれます。

R7RSとの最大限の互換性を得るにはこのモードを使ってください。

legacy

リーダは以前の(0.9.3.3及びそれ以前の)Gaucheと同じように動作します。 リーダがhash-bang指示子#!gauche-legacyに出会うと、ファイルの残りの部分は このモードで読まれます。

このモードが必要になるのは、2桁の16進数エスケープの直後にセミコロンが来ているリテラルを、 文字+セミコロンと読みたい場合だけです。例えば "\x30;a""0a"でなく"0;a"と読みたい、等。 こういうケースはコードではほとんど無いと思いますが、 データを文字列リテラルとしてダンプしてある場合、それも不完全な文字列として ダンプしてある場合に、こういった並びが出現しているかもしれません。

warn-legacy

リーダはpermissiveモードと同様に動作しますが、 旧来の16進数エスケープに出会うと警告を発します。 gosh-fwarn-legacyコマンドライン引数が与えられた場合は これがデフォルトのモードになります。

コードの中に非互換なエスケープシーケンスが無いかどうか調べるのに役立ちます。


Next: , Previous: , Up: 入力   [Contents][Index]

6.22.7.3 読み込み時コンストラクタ

SRFI-10で定義されている読み込み時コンストラクタは、ユーザ定義の構造の 外部表現を作るための簡単な方法を提供します。

Reader Syntax: #,(tag arg …)

[SRFI-10] Gaucheはtag (シンボル)をコンストラクタ手続きに関連付ける グローバルなテーブルを管理しています。

リーダーがこの構文に出会ったとき、arg …を読み込み、 tagに関連付けられた読み込みコンストラクタを探し、 arg …を引数としてそのコンストラクタを呼び出し、 その構文を読み込んだ結果としてそのコンストラクタが返した値を挿入します。

この構文はリーダー内部で処理されることに注意して下さい。評価器は argを見ず、リーダーが返したオブジェクトしか見ません。

Function: define-reader-ctor tag procedure

[SRFI-10] 読み込みコンストラクタproceduretagに関連付けます。

例:

(define-reader-ctor 'pi (lambda () (* (atan 1) 4)))

#,(pi) ⇒ 3.141592653589793

'(#,(pi)) ⇒ (3.141592653589793)

(define-reader-ctor 'hash
  (lambda (type . pairs)
    (let ((tab (make-hash-table type)))
      (for-each (lambda (pair)
                  (hash-table-put! tab (car pair) (cdr pair)))
                pairs)
      tab)))

(define table
 #,(hash eq? (foo . bar) (duh . dah) (bum . bom)))

table ⇒ #<hash-table eq? 0x80f9398>
(hash-table-get table 'duh) ⇒ dah

write-objectメソッド(出力参照)と組み合わせて、 読み戻ることが可能なフォームで書かれたユーザ定義のクラスを 作ることが簡単になります。

(define-class <point> ()
  ((x :init-value 0 :init-keyword :x)
   (y :init-value 0 :init-keyword :y)))

(define-method write-object ((p <point>) out)
  (format out "#,(<point> ~s ~s)" (ref p 'x) (ref p 'y)))

(define-reader-ctor '<point>
  (lambda (x y) (make <point> :x x :y y)))

注意: define-reader-ctorの効果の範囲はSRFI-10には 規定されておらず、SRFI-10をサポートする実装においても互換性の問題を 起こすことがあるかもしれません。 (実際に、define-reader-ctorの存在そのものが実装の選択に 任されています。)

Gaucheでは、現時点においては、define-reader-ctorはそのフォームが コンパイルされ評価された時点で効力を持ちます。 Gaucheはトップレベルのフォームを順番にコンパイル・評価するので、 define-reader-ctorで指定されたtagは、その指定の直後から 使えます。 しかし、define-reader-ctorの呼び出しとtagの使用が beginフォームで囲まれている場合は、beginフォーム全体は 評価される前に一度にコンパイルされるため、うまく動作しません。

他の実装では、define-reader-ctorの呼び出しが効力を持つようにする 前にファイル全体を読み込むことを要求するかも知れません。 その場合は、define-reader-ctorと定義されたtagの使用を 同じファイルに置く事は実質的に不可能です。 可能ならば、define-reader-ctorの呼び出しと、tagの使用は 異なるファイルに分離されることが望まれます。

現在のdefine-reader-ctorに関するもう1つの問題は、それが Gaucheシステムのグローバルテーブルを変更してしまうことで、それゆえに モジュール性が良くありません。 複数人によって書かれたコードは同じタグを使っているかも知れず、 期待されない結果を引き起こすかも知れません。 作者にはまだ明確なアイデアがありませんが、将来のバージョンでは、 Gaucheにはtagのスコープをカプセル化する方法が導入されるかも しれません。


Previous: , Up: 入力   [Contents][Index]

6.22.7.4 入力ユーティリティ手続き

Function: port->string port
Function: port->list reader port
Function: port->string-list port
Function: port->sexp-list port

便利な入力手続きです。APIはScshとSTkから取りました。

port->stringportをEOFまで読み込み、 読んだものを文字列として返します。

port->listは手続きreaderportに繰り返し適用し、 結果をリストに蓄積します。readerがEOFを返したら 蓄積されたリストを返します。 port自体はクローズされないことに注意してください。

port->string-listport->listread-lineで特定化したもので、 port->sexp-listport->listreadで特定化したものです。

もし入力にGaucheの内部エンコーディングにおいて有効な文字をつくらない バイト列が含まれていた場合、port->stringport->string-list の返り値には不完全な文字列が含まれている可能性があります。 入力をバイナリデータとして扱いたい場合は、 gauche.uvectorport->uvectorを使って下さい (ユニフォームベクタのブロック入出力参照)。

Function: port-fold fn knil reader
Function: port-fold-right fn knil reader
Function: port-for-each fn reader
Function: port-map fn reader

readerによって読まれる入力に対する便利な繰り返し手続きです。

実際にはこれらの手続きはポートからの入力以外にも使えるため、それぞれ generator-fold, generator-fold-right, generator-for-each, generator-mapによって置き換えられました。 詳しくは生成された値の畳み込みを参照してください。

これらの手続きは後方互換性のためだけに提供されています。


Previous: , Up: 入出力   [Contents][Index]

6.22.8 出力


Next: , Previous: , Up: 出力   [Contents][Index]

6.22.8.1 出力ルーチンの階層

Gaucheにはたくさんの出力手続きがあり、慣れないうちはどれを使えばよいか迷ってしまう かもしれません。次の表は様々な出力手続きを分類するものです。

オブジェクトの出力

Schemeオブジェクトを出力する手続きです。 もっと低レベルの手続きもありますが、一般にはこの層が出力ルーチンの基本であると みなされています。Schemeのオブジェクト単位で操作をするからです。 この手続き群はさらに次の二つのグループに分かれます。

高レベル整形出力

出力を指定の桁数に揃えたり、どちらかに寄せたり、といった書式を指定できる手続きが formatです。Cのprintfのようなものです。

低レベル、特定の型用の出力

「生」のデータを扱う手続きです。


Next: , Previous: , Up: 出力   [Contents][Index]

6.22.8.2 出力制御

Lisp構造の出力形式は、 <write-controls>オブジェクトによって制御することができます。 Lispオブジェクトを出力するルーチン(write, display等)や、 高レベル出力手続き(format等)は出力制御オブジェクトを取ることができます。

以下の例で、出力制御の様子がわかると思います。

(write '(1 10 100 1000)
       (make-write-controls :print-base 16 :print-radix #t))
 prints (#x1 #xa #x64 #x3e8)

(write (iota 100)
       (make-write-controls :print-length 5))
 prints (0 1 2 3 4 ...)

make-write-controls手続きは出力制御オブジェクトを作って返します。 出力制御オブジェクトは以下のスロットを持ちます (これらのスロット名はCommon Lispの対応するプリント制御変数から取られました)。

print-length

このスロットが非負整数の場合、それはリストとベクタ(ユニフォームベクタを含む)の 要素が表示される最大数を指定します。もしリストやベクタがその最大数より 多くの要素を持っている場合、残りの要素は表示されず、代わりに ...が表示されます。このスロットが#f(デフォルト)であれば、 すべての要素が表示されます。

print-level

このスロットが非負整数の場合、それは構造体(リストとベクタ)が表示される 最大の深さを指定します。もし構造体がより深いノードを持っている場合、 そのノードの代わりに#が表示されます。 このスロットが#f(デフォルト)であれば、すべての要素が表示されます。

print-base

このスロットは2以上36以下の整数でなければならず、 正確な整数を印字する基数を指定します。デフォルトは10です。

print-radix

このスロットは真偽値を持ちます。真であれば、 正確な整数の前に常に基数プレフィクスが表示されます。 デフォルトは#fです。

出力制御オブジェクトは変更不可です。もし既に存在する制御オブジェクトを 少し変えたものが欲しければ、write-controls-copyが使えます。

Function: make-write-controls :key print-length print-level print-base print-radix

出力制御オブジェクトを返します。

Function: write-controls-copy controls :key print-length print-level print-base print-radix

出力制御オブジェクトcontrolsのコピーを返します。もしキーワード引数が 与えられれば、その要素が置き換えられます。

高レベル出力手続きはwrite-objectメソッドを経由して再帰的に 呼ばれる可能性があります。その場合、大元の出力手続き呼び出しに渡された 出力制御オブジェクトが、同じポートに対して出力する再帰的に呼ばれる 出力手続きへと自動的に引き継がれます。


Next: , Previous: , Up: 出力   [Contents][Index]

6.22.8.3 オブジェクトの出力

以下の手続きで、省略可能な引数portは出力ポートでなければなりません。 省略された場合が現在の出力ポートが使われます。

いくつかの手続きはport/controls引数を取ります。これは、出力ポート もしくは<write-controls>オブジェクトでなければなりません。例えば writeは二つまでそういった引数を取ります。すなわち、writeは 以下のいずれの形式でも呼び出すことができます: (write obj)(write obj port)(write obj contorls)(write obj port controls)(write obj controls port)。 省略された場合、ポートは現在の出力ポート、出力制御についてはデフォルトの出力制御が 使われます。

Function: write obj :optional port/controls1 port/controls2
Function: write-shared obj :optional port/controls1 port/controls2
Function: write-simple obj :optional port/controls1 port/controls2

[R7RS+] write族の手続きは、Schemeオブジェクトの外部表現を出力します。 外部表現は一般に、read手続きによって読み戻せば、 元のオブジェクトと同等のオブジェクトとなります。 この3つの手続きの違いは、共有構造および循環構造の扱いにあります。

writeは循環構造に対して安全です。データに循環がある場合は データラベル記法(#n=#n#)を用いてそれを表現します。 循環の無い、単に共有されているだけの構造についてはデータラベル記法を使いません (二番目の例参照)。

(let1 x (list 1)
  (set-cdr! x x)   ; create a cycle
  (write x))
 ⇒ shows #0=(1 . #0#)

(let1 x (list 1)
  (write (list x x)))
 ⇒ shows ((1) (1))

write-sharedも循環構造に対して安全で、さらに共有構造も データラベル記法で表示します。グラフ構造のトポロジーを維持する必要がある 場合はこの手続きを使ってください。

(let1 x (list 1)
  (write (list x x)))
 ⇒ shows (#0=(1) #0#)

最後に、write-simpleはオブジェクトを、共有構造や循環構造を考慮せずに 再帰的に表示します。これは出力前に共有構造の検出パスを走らせる必要がないので 高速です。しかし、渡されたデータに循環があった場合は出力が止まらなくなります。

これらの手続きが表示中にユーザ定義クラスのオブジェクトに 出会った場合は、ジェネリックファンクションwrite-objectを呼び出します。

歴史的経緯: writeは以前のScheme標準にもありましたが、 循環構造があった場合の振る舞いはR7RSになるまで規定されていませんでした。 実際、Gauche 0.9.4より前のwriteは、循環構造を渡されると停止しません。 SRFI-38はデータラベル記法および、それを表示するための write-with-shared-structurewrite/ss手続きを導入し、 Gaucheもそれをサポートしていました。 R7RSでこの問題は明確にされ、Gaucheも0.9.4からそれに沿っています。

Function: write-with-shared-structure obj :optional port
Function: write/ss obj :optional port
Function: write* obj :optional port

[SRFI-38] これらは上記のwrite-sharedの別名です。

Gaucheは、STklosから取ったwrite*という名前を長く使ってきましたが、 srfi-38によってwrite-with-shared-structurewrite/ssが 定義されました。これらの名前は互換性のためだけに残してあります。 新たなコードにはwrite-sharedを使ってください。

Function: display obj :optional port/controls1 port/controls2

[R7RS] オブジェクトobjの人に読みやすい表現を、出力ポートに書き出します。

objが循環構造を含んでいる場合は、データラベル記法を使って出力します。

displayが表示中にユーザ定義クラスのオブジェクトに 出会った場合は、ジェネリックファンクションwrite-objectを呼び出します。

(display "\"Mahalo\", he said.")
 ⇒ shows "Mahalo", he said.

(let ((x (list "imua")))
  (set-cdr! x x)
  (display x))
 ⇒ shows #0=(imua . #0#)
Function: print expr …

expr … をdisplayを使って現在の出力ポートに表示し、 最後に改行を書き出します。

Method: write-object (obj <object>) port

このメソッドをつかって、オブジェクトをどのように印字するかをカスタマイズ できます。

Function: newline :optional port

[R7RS] portに改行文字を書き出します。(write-char #\newline port)(display "\n" port)と書いても同じことですが、歴史的な理由から 残されています。


Next: , Previous: , Up: 出力   [Contents][Index]

6.22.8.4 フォーマット出力

Function: format dest controls string arg …
Function: format controls dest string arg …
Function: format dest string arg …
Function: format controls string arg …
Function: format string arg …

[SRFI-28+] string の指示に従い、arg …をフォーマットします。 この手続きはCommonLispのformatのサブセットに、Gauche独自の拡張を 加えたものです。また、これはSRFI-28 "Basic format strings" のスーパーセットに なっています (SRFI-28)。

dest引数は出力先を指定します。それが出力ポートであれば、フォーマットされた 結果はそのポートに書き出されます。port#tであれば、結果は 現在の出力ポートに書き出されます。port#fであれば、結果は 文字列としてformatから返されます。 destは省略することもできます。その場合は、dest#f を指定したのと同じ動作をします(SRFI-28のformat)。

controls引数は<write-controls>オブジェクトで、 ~s~aの出力に影響を与えます (出力制御参照)。これはGauche独自の拡張です。

(formatの関数シグネチャはちょっと変わっていますが、 これは便利さを優先したためです。portcontrolsはどちらも省略可能で、 またどの順序でも指定できます。)

stringはフォーマット指示子を含んだ文字列です。 フォーマット指示子はチルダ‘~’から始まり、特定の文字で終了する文字の並びで、 それぞれのフォーマット指示子が対応するargを取りフォーマットします。 string内のフォーマット指示子以外の文字列はそのまま出力されます。

(format #f "the answer is ~s" 42)
  ⇒ "the answer is 42"

フォーマット指示子は一つ以上のコンマで区切られたパラメータを取ることもできます。 パラメータは整数か文字です。文字の場合、クオート文字に続けてその文字を置きます。 パラメータが省略された場合は既定値が使われます。パラメータの意味はフォーマット指示子毎に 異なります。

さらに、フォーマット指示子は2種類のフラグ、‘@’ と ‘:’ を 取ることができます。これらの組合せでフォーマットの動作が変わります。フラグは (もしあれば)パラメータの後、指示子の文字の直前に置かれなければなりません。

パラメータの位置に文字 ‘v’ か ‘V’ を置くこともできます。 その場合、パラメータの値が引数リストから取られます。対応する引数は整数か 文字、または#fでなければなりません。#fの場合はそのパラメータが 省略されたのと同じになります。

いくつかの例です。

~10,2s

パラメータ10と2を伴う、フォーマット指示子~s

~12,,,'*A

第1パラメータに数値12、第4パラメータに文字‘*’を取るフォーマット指示子~a。 第2と第3のパラメータは省略されています。

~10@d

フォーマット指示子~d。パラメータ10と‘@’フラグがついています。

~v,vx

フォーマット指示子~x。第1パラメータと第2パラメータは引数リストから取られます。

以下にサポートされているフォーマット指示子を示します。フォーマット指示子の文字自体は 大文字であっても小文字であっても構いません。特に断りのない限り両者は同じ動作をします。

~mincol,colinc,minpad,padchar,maxcolA

ASCII出力。対応する引数がdisplayを使ってフォーマットされます。 整数がmincolに与えられた場合、それは出力される最小の文字数を指定します。 引数のフォーマット結果がmincolより短ければ、空白が右に追加されます(つまり、 左詰めになります)。

colincminpad、そしてpadcharは更に細かいパディング方法を 指定します。padcharに文字が与えられた場合、それが空白文字の代わりにパディング文字と して使われます。minpadに0以上の整数が与えられた場合、少なくともその数だけの パディング文字が追加されます。colincが指定された場合、 追加されるパディング文字の数がcolincの倍数に調整されます。

アトマーク ‘@’ フラグが与えられた場合、結果は右詰めになります。

maxcolパラメータは与えられていれば書かれる文字数の上限を指定します。 フォーマット後の文字列の長さがmaxcolを超えた場合、maxcol文字だけが 書かれます。コロン ‘:’ フラグが同時に与えられていれば、 maxcol - 4 文字が書かれた後、文字列“ ...”が書かれます。

(format #f "|~a|" "oops")
  ⇒ "|oops|"
(format #f "|~10a|" "oops")
  ⇒ "|oops      |"
(format #f "|~10@a|" "oops")
  ⇒ "|      oops|"
(format #f "|~10,,,'*@a|" "oops")
  ⇒ "|******oops|"
(format #f "|~10,,,'☆a|" "oops")
  ⇒ "|oops☆☆☆☆☆☆|"

(format #f "|~,,,,10a|" '(abc def ghi jkl))
  ⇒ "|(abc def gh|"
(format #f "|~,,,,10:a|" '(abc def ghi jkl))
  ⇒ "|(abc de ...|"
~mincol,colinc,minpad,padchar,maxcolS

S式出力。対応する引数がwriteを使ってフォーマットされます。 パラメータの意味は~A指示子と同じです。

(format #f "|~s|" "oops")
  ⇒ "|\"oops\"|"
(format #f "|~10s|" "oops")
  ⇒ "|\"oops\"    |"
(format #f "|~10@s|" "oops")
  ⇒ "|    \"oops\"|"
(format #f "|~10,,,'*@s|" "oops")
  ⇒ "|****\"oops\"|"
(format #f "|~10,,,'★s|" "oops")
  ⇒ "|\"oops\"★★★★|"
~mincol,padchar,commachar,intervalD

10進出力。対応する引数が10進数表記でフォーマットされます。もし引数が数値でなければ、 全てのパラメータは(‘v’パラメータの処理後に)無視され、 引数は~Aでフォーマットされます。

もしmincolに整数が与えられたら、それが最小の文字数を指定します。 結果の文字数がそれより少なければ、文字padcharが左に追加されます(右詰めになります)。 padcharが省略された場合は空白文字が使われます。

(format #f "|~d|" 12345)
  ⇒ "|12345|"
(format #f "|~10d|" 12345)
  ⇒ "|     12345|"
(format #f "|~10,'0d|" 12345)
  ⇒ "|0000012345|"

アトマーク ‘@’ フラグが与えられた場合、正の引数に対して ‘+’ が 先頭につけられます。

コロンフラグ ‘:’ が与えられた場合、結果の文字はinterval文字毎に まとめられ、間に文字commacharが挿入されます。デフォルトでは3文字毎にコンマが 挿入されます。

(format #f "|~:d|" 12345)
  ⇒ "|12,345|"
(format #f "|~,,'_,4:d|" -12345678)
  ⇒ "|-1234_5678|"
~mincol,padchar,commachar,intervalB

2進出力。対応する引数が2進数の整数としてフォーマットされます。 パラメータの意味は~Dと同じです。

~mincol,padchar,commachar,intervalO

8進出力。対応する引数が8進数の整数としてフォーマットされます。 パラメータの意味は~Dと同じです。

~mincol,padchar,commachar,intervalX
~mincol,padchar,commachar,intervalx

16進出力。対応する引数が16進数の整数としてフォーマットされます。 フォーマット指示文字に ‘X’ が与えられた場合は ‘ABCDEF’ が桁文字として 使われ、 ‘x’ が与えられた場合は ‘abcdef’ が桁文字として使われます。 パラメータの意味は~Dと同じです。

(format #f "~8,'0x" 259847592)
  ⇒ "0f7cf5a8"
(format #f "~8,'0X" 259847592)
  ⇒ "0F7CF5A8"
~count*

引数のカウンタをcountだけ後方にずらします。つまり、count個の引数が 無視されることになります。countのデフォルト値は1です。 コロンフラグが与えられた場合は引数カウンタを前方に動かします。 例えば~:*は次のディレクティブが直前に使った引数を再び使うようにします。 アトマークフラグが与えられた場合は、countが引数の絶対位置を示します。 0が最初の引数です。


Previous: , Up: 出力   [Contents][Index]

6.22.8.5 低レベル出力

Function: write-char char :optional port

[R7RS] 文字charをポートに出力します。

Function: write-byte byte :optional port

出力ポートに1バイトのデータbyteを書き出します。 byteは0から255の間の正確な整数でなければなりません。

この手続きはR7RSではwrite-u8と呼ばれています。

Function: flush :optional port
Function: flush-all-ports

それぞれ、port、および全てのポートにバッファされているデータを 全て書き出します。

手続き"flush"はScheme実装によって様々な名前で呼ばれています: force-output (Scsh, SCM)、 flush-output (Gambit)、flush-output-port (Bigloo) 等。 flushの名前はSTkとSTklosから取りました。 R7RSではflush-output-portを採用しています。


Footnotes

(1)

ある意味、 これは他のプログラミング言語でシリアライズやマーシャライズと呼ばれている操作に 似ています。一般のSchemeオブジェクトをディスクやネットワークにwriteして、 それをreadすれば、元のオブジェクトと等価なオブジェクトが得られるわけです。 Lisp族言語では、これはread/write invarianceと呼ばれ、組み込みの機能と なっています。但しオブジェクトによってはこの性質を持たないものもあり、 そういうオブジェクトを扱う時は専用のシリアライザを書く必要があります。


Previous: , Up: 出力   [Contents][Index]