Schemeを覚える3(入出力1)

今日はファイルの読み込みのみ。
Scheme 入門 9. 入出力にあるコードを読み解く。

> (define (read-file file-name)                    ;関数の定義
    (let ((p (open-input-file file-name)))         ;p変数に入出力ポートを設定
      (let loop((ls1 '()) (c (read-char p)))       ;名前つきletでループ、ls1を空のリストで初期化、cをポートから読みとった一文字で初期化
        (if (eof-object? c)                        ;cがファイルの終端かどうか判断
            (begin                                 ;begin内の処理をまとめて行う
              (close-input-port p)                 ;入出力用ポートを閉じる
              (list->string (reverse ls1)))        ;ls1リストに入っている文字列を”逆順で”出力
            (loop (cons c ls1) (read-char p))))))  ;新しいリストを作る(セットされる文字は常にリスとの先頭に。つまり逆順でリストに追加されていく)。次の文字を読み込み。

これを実行した結果が

> (read-file "/home/hironemu/hello.txt")
"Hello world!\nScheme is an elegant programming language\n"
> (display (read-file "/home/hironemu/hello.txt"))
Hello world!
Scheme is an elegant programming language

と、このようにファイルの内容が出力される。そういえば名前つきletを勉強してなかったなー。

(let loop((ls1 '()) (c (read-char p)))

この行で、変数の初期化する部分にloopって名前をつけておき、局所変数ls1とcを初期化しておき

(loop (cons c ls1) (read-char p))))))

この行で、さっき名前をつけたloopってやつを呼び出して変数の内容を更新している。(cons c ls1)の結果がls1に、(read-char p)の結果がcに入るんだと思うw、そうなるもんだと覚えるべきか。とりあえず今のところはそうしとこう。

ファイル読み込み(一文字ずつ)をRubyでやるとこうなる

#!/usr/bin/ruby

ls1 = [] # 配列の初期化
open("/home/hironemu/hello.txt") {|f|
  while(c = f.getc) # 一文字ずつ読み込み、cへ代入
    ls1 << c.chr # getcはASCIIコードを返すのでchrメソッドで文字に変換、そしてls1へ追加していく
  end
}
puts ls1.join # joinで配列を連結して出力

実行結果

$ ./read.rb 
Hello world!
Scheme is an elegant programming language

ちなみにファイルをクローズしてないのはopne関数の中でクローズの処理をやってくれてるから。openにコードブロック({|f|〜}<この部分)を渡してる時は、勝手にやってくれてるんですねー。便利。