Parenist養成ゼミ: 入出力
この記事は、Parenist養成ゼミシリーズの記事である。
今回は、入出力というテーマで講義を行った。プログラムで入出力ができるようになると一気に実用的なプログラムを作成することができるようになる。
入出力関数
Parenには以下に示す読み書きの関数が備わっている。
read
read -- read S-expression.
read-byte -- read a byte.
read-bytes -- reads the specified length or all the rest.
read-char -- read a character.
read-line -- read one line.
write
write -- write S-expression.
write-byte -- write a byte.
write-bytes -- write bytes-like object.
write-line -- write bytes-like object and new line.
stream
入出力を行う対象のことをstreamという。Parenの入出力関数はstreamを動的にsymbol$in, $out
から参照する。
$in, $out
の初期値は、標準入出力である$stdin, $stdout
である。
例えば、cat
は以下のように実装できる。
(function cat ()
(let (byte nil)
(while (!= (<- byte (read-byte)) -1)
(write-byte byte))))
行単位にすると以下のようになる。
(function cat ()
(let (line nil)
(while (<- line (read-line))
(write-line line))))
Parenでは標準入出力の他にfile streamとstring streamをサポートしている。
file stream
with-open
macroを用いて、$in, $out
をfile streamに束縛することができる。
ファイル./parenrc
の読み書きを行う例を示す。
(with-open ($out "~/.parenrc" :write)
(import :datetime)
(write-line (str "; parenrc. -- this This file was generated at " (.to-s (datetime.now))))
(write '(write-line "You must have a lot of time on your hands"))
(write '(write-line)))
(with-open ($in "~/.parenrc" :read)
(write-line (read-line))
(while (write (read))))
string stream
with-memory-stream
macroを用いて、$in, $out
をstring streamに束縛することができる。
(with-memory-stream ($in "aaline\n(+ (- 3 2) 4))")
(write (read-byte))
(write (read-char))
(write (read-line))
(write (read)))
(with-memory-stream ($out)
(write-byte 97)
(write-bytes "a")
(write-line "line")
(write (list '+ (list '- (+ 1 2) 2) (+ 2 2))))
課題
以下のPOSIXコマンドを実装せよ。
- head(1)
- nl(1)
- tail(1)
- tee(1)
- seq(1)
- uniq(1)
- ファイル名を引数とし、そのファイルの各行をlistとして返す関数
flie->list
を実装せよ。 - ファイル名を引数とし、そのファイルのS式をread & evalする関数
%load
を実装せよ。 - ファイル名を引数とし、そのファイルのS式の数を返す関数
count-expr
を実装せよ。 - ファイル名を引数とし、そのファイルのsymbolのlistを返す関数
file->symbol-list
を実装せよ。