Racket: Racket における入出力
はじめに
この記事では、関数型プログラミング言語であるRacketの基本的な入出力関数について、具体的なサンプルプログラムを用いて説明します。
これにより、Racketプログラムで入出力を実装し、実際のプロジェクトに応用できます。
ここでは、Racketの主要な入出力関数を紹介し、それぞれの機能と使用例を説明しています。
詳細は Racket Reference を参照して、その他の関数や使用例を確認してください。
1. ポートと標準入出力
Racketの入出力関数は、ポートを指定して使用できます。
ポートは、ファイル、ネットワークなどの入出力を統一して管理するRacketの重要なオブジェクトです。
Racketの入出力関数は、ポート越しにデータを入力、出力します。
ポートを指定しないときは、標準入力/標準出力ポートが使用されます。
read関数は、ポートを指定しない場合、標準入力からデータを読み込みます。
write, print, displayの各関数は、ポートを指定しない場合、標準出力にデータを出力します。
通常の入出力関数を使った (ポートを指定しない) Racketプログラムは、コンソールからの入力やパイプ・リダイレクトに対応しています。
これにより、ユーザーはプログラムの入出力を柔軟に操作できます。
2. 入力関数
2.1 read関数の詳細
read関数は、入力データをRacketのデータ型として解釈して返します。
入力データがRacketのデータとして正しくない場合、エラーが発生します。
たとえば、リストの(が)ではなく]で閉じられている場合に、エラーが発生します。
下記のプログラムは、ユーザーからの入力を読み取り、その入力とデータ型を出力します。
EOF (End of File) (Windowsでは、Ctrl+Zキー)を入力すると、終了します。
このプログラムを実行すると、下記のようになります:
> racket .\echo-loop.rkt
--- echo ---
input: abc
output: 'abc - symbol
input: 42
output: 42 - number
input: "hello"
output: "hello" - string
input: #\k
output: #\k - character
input: [1 . 2]
output: '(1 . 2) - pair
input: '(1 2 3)
output: ''(1 2 3) - list
input: ^Z
output: #<eof> - unknown
2.2 ファイルからの入力
ファイルからデータを読み取るには、ファイルポートを使用します。
ファイル入力の例は、次のようになります:
(define fin (open-input-file "data.txt"))
(define data (read fin))
(printf "read data: ~a\n" data)
(close-input-port fin)
2.3 文字の入力
read関数には、文字入力用のread-char関数や行入力用のread-line関数があります。
read-char関数は、標準入力から 1文字ずつ読み込み、read-line関数は改行までの 1行を読み込みます。
このとき、文字はUTF-8エンコードで読み込まれます。
詳細は、 Racket Referenceを参照してください。
3. 出力関数
3.1 write/print/displayの違い
write,print,displayの各関数は役割が違います。
それぞれの役割は、次の通りです:
-
write:
readで読み込んだデータを、そのままの形式で出力する。 -
print:
REPLでの出力のようにデータを出力する。文字列、シンボルなどはクオートされる。 -
display:
画面出力用に、データを出力する。文字列型、シンボル型、文字型などはクオートしない。
出力例は、下記を参照してください:
write |
print |
display |
|
|---|---|---|---|
| 1/2 (数値型) | 1/2 | 1/2 | 1/2 |
| #\x (文字型) | #\x | #\x | x |
| "hello" (文字列型) | "hello" | "hello" | hello |
| '|tea pot| (シンボル型) | '|tea pot| | '|tea pot| | tea pot |
| '("I" pod) (リスト型) | '("I" pod) | '("I" pod) | I pod |
| write (procedure) | #<procedure:write> | #<procedure:write> | #<procedure:write> |
3.2 ファイルへの出力
ファイルポートを指定すると、データをファイルに出力します。
ファイル出力には、open-output-fileを使用します。
ファイルがすでに存在する場合、open-output-file関数は例外を発生させますが、#:exists 'truncateオプションを指定することで回避できます。
このとき、Racketは、既存のファイルの内容をすべて消去し、新しい内容で上書きします。
'truncateの代わりに、#:exist 'can-updateが指定できます。
この場合、ファイルの内容は消去せず、新しい内容で上書きします。
プログラムは、次のようになります:
(define fout (open-output-file "data.txt")) ; cause exception if file is already exist
(display "howdy" fout)
(close-output-port fout)
ファイルがすでに存在する場合は、次のようなエラーが発生しますが、#:exist 'truncateオプションで回避できます:
> racket fileout.rkt
open-output-file: file exists
path: data.txt
context...:
body of
"fileout.rkt"
上記のエラーを回避するために、#:exists 'truncateを指定します:
(define fout (open-output-file "data.txt" #:exist 'truncate))
(display "howdy" fout)
(close-output-port fout)
3.3 文字の出力
read-charに対応する形で、1文字出力用にwrite-char関数があります。
write-char関数はread-charで読み込んだ 1文字を出力します。
read-line関数は、通常のwrite関数を使って出力します。
おわりに
この記事では、Racketの入出力関数について基本的なことを説明しました。
これらの関数を駆使することで、外部からのデータ入力などに対応した実践的なプログラムを作成できます。
Racketの学習を深め、関数型プログラミング言語の技能を向上させ、より洗練したプログラムを書けるようになりましょう。
それでは、Happy Hacking!
技術用語と注釈
技術用語について、その注釈を箇条書きにします。
-
read関数:
入力されたデータを、Racketのデータとして解釈し、型付けされたデータとして返す関数。 -
write関数:
Racketのデータ型を元の形式で出力する関数。 -
print関数:
RacketのデータをREPLで使用される形式で出力する関数。 -
display関数:
データをクオートしないシンプルな形式で出力する関数。 -
ポート:
データを関数を通じて入出力するための、Racketのオブジェクト。 -
ファイルポート:
ファイルへの入出力を行なうためのポート。
参考資料
Webサイト
-
Racket Guide:
Racket Guideの入出力の章 -
Racket Reference:
Racket Referenceの入出力の章
Discussion