[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

16. Lispオブジェクトの読込みと印字

印字(print)読込み(read)は、Lispオブジェクトをテキス ト形式へ、またその逆に変換するための操作です。これらは、Lisp のデータ型で述べられている印字表現とリード構文を扱うものです。

この章では、読込みと印字のためのLisp関数について述べます。また、どこから テキストを得るか(読込みの場合)、あるいはどこへ出力するか(印字の場合)を指 定する、ストリーム(stream)についても述べます。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

16.1 読込みと印字の概論

Lispオブジェクトの読込み(read)とは、テキスト形式のLisp式を解析 して、対応するLispオブジェクトを生成することを意味します。これは、Lispプ ログラムが、LispコードのファイルからLispの世界に入り込むための方法です。 このテキストを、そのオブジェクトのリード構文(read syntax)と呼びま す。たとえばテキスト`(a . 5)'は、CARaCDRが数 値5であるコンス・セルのリード構文です。

Lispオブジェクトの印字(print)とは、オブジェクトを表現するテキス トの生成、つまりオブジェクトからその印字表現への変換を意味します。上述の コンス・セルの印字では、`(a . 5)'というテキストが生成されます。

読込みと印字は、多かれ少なかれ逆の操作であるといえます。与えられた一片の テキストの読込みによって生成されるオブジェクトの印字は、たいてい同じテキ ストを生成し、あるオブジェクトの印字によって生成されるテキストの読込みは、 通常、同様なオブジェクトを生成します。たとえば、シンボルfooの印字 はテキスト`foo'を生成し、そのテキストの読込みはシンボルfooを 返します。要素がabであるリストの印字はテキスト`(a b)'を生成し、そのテキストの読込みは、abを要素とするリス ト(同じリストそのものではありませんが)を生成します。

しかしながら、厳密にはこれら二つの操作は逆ではありません。三種類の例外が あります:


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

16.2 入力ストリーム

テキスト読込み用のLisp関数のほとんどは、引数として入力ストリーム (input stream)を取ります。入力ストリームは、読み込むべきテキスト文字群 をどこから、あるいはどのように得るのかを指定するものです。入力ストリーム として使用可能な型には、以下のようなものがあります:

バッファ

入力文字群は、バッファから読み込まれます。ポイント直後の文字から読 み始められます。ポイントは、読み込まれた文字数分だけ進みます。

マーカ

入力文字群は、マーカがあるバッファから読み込まれます。そのマーカの 直後の文字から読み始められます。マーカの位置は、読み込まれた文字数分だけ 進みます。ストリームがマーカである場合、そのバッファのポイント値は何ら影 響を受けません。

文字列

入力文字群は、文字列から取られます。その文字列の先頭の文字から読み 始められ、必要なだけの文字が使われます。

関数

入力文字群は、関数によって、その呼出しごとに一文字ずつ生成されます。 普通、その関数は、引数なしで呼び出されて一文字を返すものです。

時折、関数は、一つの引数(常に一文字)を以て呼び出されることがありま す。その場合、関数はその引数を保存し、次回の呼出しでそれを返すよう に準備します。これは、文字の読戻し(unread)と呼ばれます。Lispリー ダが一文字余分に読み込んでしまい、"それを読込み元へ戻したい"というとき に行なわれます。

t

ストリームとして用いられるtは、入力がミニバッファから読み込まれる ことを意味します。実際には、一度ミニバッファが呼び出され、そこでユーザに よって与えられたテキストが、後で入力ストリームとして用いられる文字列へと 変換されます。

nil

入力ストリームとして与えられたnilは、その代わりに変数 standard-inputの値を使用することを意味します。その値は、デフォ ルト入力ストリーム(default input stream)であり、非nil入力ストリー ムでなくてはなりません。

シンボル

入力ストリームとしてのシンボルは、そのシンボルの関数定義(もしあれば)と等 価です。

バッファ・ストリームからの読込みの例を、その前後でポイントがどこに位置す るかを記しながら、以下に示します:

 
---------- Buffer: foo ----------
This∗ is the contents of foo.
---------- Buffer: foo ----------

(read (get-buffer "foo"))
     ⇒ is
(read (get-buffer "foo"))
     ⇒ the

---------- Buffer: foo ----------
This is the∗ contents of foo.
---------- Buffer: foo ----------

最初の読込みでスペースをスキップしていることに注意してください。読込みは、 意味のあるテキストに先行するどんな量の空白もスキップします。

Emacs 18においては、シンボルの読込みは、そのシンボルを終結しているデリミ タを捨てていました。つまりポイントは、`the'の後ろではなく `contents'の先頭に位置したでしょう。Emacs 19の挙動は、あるオブジェ クトの終りとなる開括弧が別のオブジェクトの先頭として必要となる、 `bar(foo)'のような入力を正しく扱えるので、より優れています。

以下に、バッファの先頭に配置されたマーカ・ストリームからの読込みの例を示 します。readの値は、シンボルThisです。

 
---------- Buffer: foo ----------
This is the contents of foo.
---------- Buffer: foo ----------

(setq m (set-marker (make-marker) 1 (get-buffer "foo")))
     ⇒ #<marker at 1 in foo>
(read m)
     ⇒ This
m
     ⇒ #<marker at 5 in foo>   ;; 最初のスペースの前。

文字列の内容から読み込んでみましょう:

 
(read "(When in) the course")
     ⇒ (When in)

以下の例では、ミニバッファから読み込んでいます。プロンプトは `Lisp expression: 'です(ストリームtから読み込むときは、 常にこのプロンプトが用いられます)。ユーザの入力は、そのプロンプトに続け て表示されます。

 
(read t)
     ⇒ 23
---------- Buffer: Minibuffer ----------
Lisp expression: 23 RET
---------- Buffer: Minibuffer ----------

最後に、useless-streamと名づけられた関数ストリームの例を示します。 このストリームを使用する前には、変数useless-listを文字のリストで 初期化します。その後、関数useless-streamを呼び出すごとに、このリ スト中の次の文字を獲得するか、あるいはリストの先頭に文字をつけ加えること によりその文字を読み戻します。

 
(setq useless-list (append "XY()" nil))
     ⇒ (88 89 40 41)

(defun useless-stream (&optional unread)
  (if unread
      (setq useless-list (cons unread useless-list))
    (prog1 (car useless-list)
           (setq useless-list (cdr useless-list)))))
     ⇒ useless-stream

では、このように構築されたストリームを使用して読み込んでみます:

 
(read 'useless-stream)
     ⇒ XY

useless-list
     ⇒ (40 41)

リスト中に開括弧と閉括弧が残っていることに注意してください。Lispリーダは 開括弧に出くわし、それが入力の終りであると判断して開括弧を読み戻したので す。ここで、もう一度このストリームからの読込みを試みると、`()'を読 み込み、nilを返すでしょう。

Function: get-file-char

この関数は、load関数でオープンされた入力ファイルからの読込みを行 なう入力ストリームとして、内部的に使用されます。自分自身では、この関数を 使用しないでください。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

16.3 入力関数

この節では、読込みに関するLisp関数と変数について述べます。

以下の関数群において、streamは、入力ストリーム(前節参照)を表わして います。streamnilであるか、あるいは省略された場合、変数 standard-inputの値がそのデフォルトとなります。

読込みが、終結されていないリスト、ベクタ、あるいは文字列に出会うと、 end-of-fileエラーが通知されます。

Function: read &optional stream

この関数は、streamからテキスト形式のLisp式を一つ読み込み、それを Lispオブジェクトとして返します。これは、基本的なLisp入力関数です。

Function: read-from-string string &optional start end

この関数は、string内のテキストから最初のLisp式を読み込みます。そし て、CARがその式で、CDRstring内の次の文字(まだ読み込ま れていない最初の文字)の位置を示す整数である、コンス・セルを返します。

startが与えられた場合、読込みは、string内の添字startの 位置から始められます(最初の文字が添字0)。また、endが与えられた場合、 読込みは、文字列の残りがなかったかのように、その添字の位置の直前で停止し ます。

例:

 
(read-from-string "(setq x 55) (setq y 5)")
     ⇒ ((setq x 55) . 11)
(read-from-string "\"A short string\"")
     ⇒ ("A short string" . 16)

;; 最初の文字から読み始める。
(read-from-string "(list 112)" 0)
     ⇒ ((list 112) . 10)
;; 2番目の文字から読み始める。
(read-from-string "(list 112)" 1)
     ⇒ (list . 5)
;; 7番目の文字から読み始めて、
;;   9番目で停止する。
(read-from-string "(list 112)" 6 8)
     ⇒ (11 . 8)
Variable: standard-input

この変数は、readが、stream引数がnilのときに用いる、 デフォルト入力ストリームを持っています。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

16.4 出力ストリーム

出力ストリームは、印字によって生成される文字で以て何をするのかを指定しま す。ほとんどの印字関数は、オプション引数として出力ストリームを受け付けま す。出力ストリームとして使用可能な型には、以下のようなものがあります:

バッファ

出力文字群は、バッファのポイントへ挿入されます。ポイントは、挿入さ れた文字数分だけ進みます。

マーカ

出力文字群は、マーカが指しているバッファの、そのマーカの位置へ挿入 されます。マーカの位置は、挿入された文字数分だけ進みます。ストリームがマー カである場合、そのバッファのポイント値は何ら影響を受けません。

関数

出力文字群は、それらを別の場所へストアする責任をもつ関数に渡されま す。その関数は、引数として一文字を取り、出力されるべき文字数分の回数呼ば れます。受け取った文字で何をするかはまったく自由です。

t

出力文字群は、エコー領域に表示されます。

nil

出力ストリームとして指定されたnilは、その代わりに変数 standard-outputの値を使用することを意味します。その値は、デ フォルト出力ストリーム(default output stream)であり、非nil出力ス トリームでなくてはなりません。

シンボル

出力ストリームとしてのシンボルは、そのシンボルの関数定義(もしあれば)と等 価です。

正当な出力ストリームの多くは、また入力ストリームとしても正当です。したがっ て入力と出力ストリームの違いは、主としてLispオブジェクトをどう使用するか の違いであり、オブジェクトの型の区別ではありません。

出力ストリームとして使用されるバッファの例を以下に示します。見てのとおり、 ポイントは最初、`the'`h'の直前に位置しています。しかし最後に も、ポイントは同じ`h'の直前に位置しています。

 
---------- Buffer: foo ----------
This is t∗he contents of foo.
---------- Buffer: foo ----------

(print "This is the output" (get-buffer "foo"))
     ⇒ "This is the output"

---------- Buffer: foo ----------
This is t
"This is the output"
∗he contents of foo.
---------- Buffer: foo ----------

では、出力ストリームとしてのマーカの使用を見てみます。マーカは最初、バッ ファfoo中の単語`the'`t'`h'の間にあります。そし て最後には、そのマーカは、同じ`h'の前に位置し続けるよう、挿入された テキストを跨いで進みました。いつものように示されたポイントの位置に注意し てください。その影響を受けていません。

 
---------- Buffer: foo ----------
"This is the ∗output"
---------- Buffer: foo ----------

m
     ⇒ #<marker at 11 in foo>

(print "More output for foo." m)
     ⇒ "More output for foo."

---------- Buffer: foo ----------
"This is t
"More output for foo."
he ∗output"
---------- Buffer: foo ----------

m
     ⇒ #<marker at 35 in foo>

以下の例は、エコー領域への出力を示しています:

 
(print "Echo Area output" t)
     ⇒ "Echo Area output"
---------- Echo Area ----------
"Echo Area output"
---------- Echo Area ----------

最後に、出力ストリームとしての関数の使用を見てみます。関数 eat-outputは、与えられた各文字を取り、それをリスト last-outputの先頭へconsします(see section コンス・セルとリストの生成)。そして最後 には、そのリストは出力されたすべての文字を含みますが、その内容は逆順になっ ています。

 
(setq last-output nil)
     ⇒ nil

(defun eat-output (c)
  (setq last-output (cons c last-output)))
     ⇒ eat-output

(print "This is the output" 'eat-output)
     ⇒ "This is the output"

last-output
     ⇒ (10 34 116 117 112 116 117 111 32 101 104 
    116 32 115 105 32 115 105 104 84 34 10)

このリストを逆にすることによって、正しい順番で出力を出せるようになります:

 
(concat (nreverse last-output))
     ⇒ "
\"This is the output\"
"

concatの呼出しは、リストを文字列へと変換するため、より明瞭にその 内容を見ることができます。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

16.5 出力関数

この節では、Lispオブジェクトの印字に用いるLisp関数について述べます。

一部のEmacs印字関数は、その出力が正しく読み込まれ得るよう、必要に応じて 出力にquote文字を付加します。Quote文字は`"'`\'です。これらは 文字列とシンボルとを区別し、また読込み時に文字列中の句読点文字がデリミタ として取られるのを防ぎます。完全な詳細については、See section 印字表現とリード構文。Quoteするかしないかの指定は、印字関数の選択によって行な います。

もし、そのテキストが再びLisp中に読み込まれるものであるなら、曖昧さを避け るため、quote文字をともなって印字するのが一番です。Lispプログラマのため に明確にLispオブジェクトを描写するのが目的なら、その場合も同様です。しか し、出力の目的が人間にとって見やすくすることであるなら、quoteなしで印字 するほうがよいでしょう。

自己参照型Lispオブジェクトの印字は、無限量のテキストを必要とします。場合 によっては、そのようなテキストの生成の試みは、スタック・オーバーフローを 引き起こします。Emacsはそのような再帰を検出し、すでに印字されているオブ ジェクトを再帰的に(訳注: 繰り返し)印字する代わりに、`#level' と印字します。たとえば以下での`#0'は、現在の印字操作のレベル0におけ るオブジェクトの再帰的参照を示しています:

 
(setq foo (list nil))
     ⇒ (nil)
(setcar foo foo)
     ⇒ (#0)

以下の関数群において、streamは、出力ストリームを表わしています(出 力ストリームの解説については前節を参照)。streamnilである か、あるいは省略された場合、変数standard-outputの値がそのデフォル トとなります。

Function: print object &optional stream

print関数は、印字のための便利な手段です。これは、objectの前 の改行に加えて、後ろにも改行を付加しつつ、objectの印字表現を streamへ出力します。Quote文字が用いられます。printobjectを返します。以下がその例です:

 
(progn (print 'The\ cat\ in)
       (print "the hat")
       (print " came back"))
     -| 
     -| The\ cat\ in
     -| 
     -| "the hat"
     -| 
     -| " came back"
     -| 
     ⇒ " came back"
Function: prin1 object &optional stream

この関数は、objectの印字表現をstreamへ出力します。 printのような出力を区切るための改行は印字しませんが、quote文字は print同様に用います。objectを返します。

 
(progn (prin1 'The\ cat\ in) 
       (prin1 "the hat") 
       (prin1 " came back"))
     -| The\ cat\ in"the hat"" came back"
     ⇒ " came back"
Function: princ object &optional stream

この関数は、objectの印字表現をstreamへ出力します。 objectを返します。

この関数は、readではなく人間が読めるような出力を生成することを意 図しており、そのためquote文字は挿入せず、文字列の前後に二重引用符もつけ ません。呼出しごとの字空けも行ないません。

 
(progn
  (princ 'The\ cat)
  (princ " in the \"hat\""))
     -| The cat in the "hat"
     ⇒ " in the \"hat\""
Function: terpri &optional stream

この関数は、streamに改行を出力します。この名前は、"terminate print"を表わしています。

Function: write-char character &optional stream

この関数は、characterstreamに出力します。characterを 返します。

Function: prin1-to-string object &optional noescape

この関数は、prin1に同じ引数を与えたときに印字されるテキストを内容 とする、文字列を返します。

 
(prin1-to-string 'foo)
     ⇒ "foo"
(prin1-to-string (mark-marker))
     ⇒ "#<marker at 2773 in strings.texi>"

noescapeが非nilの場合、出力におけるquote文字の使用が抑制さ れます(この引数は、Emacsバージョン19以降でサポートされています)。

 
(prin1-to-string "foo")
     ⇒ "\"foo\""
(prin1-to-string "foo" t)
     ⇒ "foo"

Lispオブジェクトの印字表現を文字列として得るための他の方法については、 文字と文字列間の変換formatを参照してください。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

16.6 出力に影響を与える変数

Variable: standard-output

この変数の値は、印字関数が、stream引数がnilのときに用いる、 デフォルト出力ストリームです。

Variable: print-escape-newlines

この変数が非nilの場合、文字列中の改行文字は`\n'として印字さ れ、改ページ文字は`\f'として印字されます。普通、これらの文字は、実 際の改行、改ページとして印字されます。

この変数は、関数prin1print、またそれらを使用するすべてに 影響を与えます。princには影響を与えません。以下に、prin1を 使用する例を示します:

 
(prin1 "a\nb")
     -| "a
     -| b"
     ⇒ "a
b"

(let ((print-escape-newlines t))
  (prin1 "a\nb"))
     -| "a\nb"
     ⇒ "a
b"

二つ目の式において、prin1の呼出しの間は print-escape-newlinesの局所的な束縛が効いていますが、その結果の印 字のときには効いていません。

Variable: print-length

この変数の値は、印字されるリストの要素の最大数です。印字されるリストが、 これよりも多くの要素をもっている場合、省略符号(訳注: `...')によって短縮 されます。

この値がnilの場合(デフォルト)、制限はありません。

 
(setq print-length 2)
     ⇒ 2
(print '(1 2 3 4 5))
     -| (1 2 ...)
     ⇒ (1 2 ...)
Variable: print-level

この変数の値は、丸括弧と角括弧が印字される際のネストの最大の深さです。こ の制限を越える深さのリスト、あるいはベクタは、省略符号(訳注: `...')によっ て短縮されます。nilの値(デフォルト)は、制限しないことを意味します。

この変数は、バージョン19以降に存在します。


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Yasutaka SHINDOH on September, 29 2006 using texi2html 1.76.