今回の演習に該当するSchemeの資料は、「Scheme処理系の基礎」の第1節(環境モデル)および第2節(λ閉包)にあたり、特に課題S20は5P後半から6Pの「オブジェクト指向風プログラミングの説明箇所にあたります。資料中では「読み飛ばしてください」とありますが、読み飛ばさずに演習に当たってください。
以下のプログラムが処理系で逐次的に実行されるとき、環境がどのように変化するか説明せよ。特に、let式の部分式がどのような環境で評価されるか、フレームがどのように増減するかに言及すること。レポートはテキストファイルとして作成すること。
(define a 100)
(define b 1)
(let ((a 10)
(b (+ a 1))
(c (- b 1)))
(let ((a c)
(b (+ a 1))
(c (let ((b 9))
(- b a))))
(+ a b c)))
締切: 11/21 23:59
以下のプログラムが処理系で逐次的に実行されるとき、環境がどのように変化するか説明せよ。λ閉包内部の式を評価する際の環境についても説明し、最後の行に関しては、「(h 1)」の評価とその外側の「((h 1) (+ a 5))」の評価について、別々に言及すること。レポートはテキストファイルとして作成すること。
(define a 100)
(define h (lambda (x) (lambda (y) (+ x (* a y)))))
(let ((a 0))
((h 1) (+ a 5)))
ヒント: 最後の行の「(h 1)」の評価では、そこでλ閉包が作られ、それが評価結果となっている。λ閉包とlambdaから始まる式は異なる概念なので、注意すること。
締切: 11/21 23:59
ソフトウェアが正しく動作しているかを確認しているために、その関数が何回呼ばれたかを数える関数を作成することを考える。1 引数関数f を引数として、そのような動作を行う関数である make-monitored を定義せよ。 make-monitored は、関数の呼び出し回数のカウンタを内部で保持した1引数関数を返す(ここではmfと呼称することにする)。mfは、シンボル how-many-calls? が引数である時、内部のカウンタの値を返す。また、シンボルreset-countが引数である時カウンタを0にリセットする。それ以外の入力に関しては、その入力におけるfの評価結果を返し、内部のカウンタの値を1増やすものとする。
実行例は下記の通りである。
> (define s (make-monitored sqrt))
> (s 100)
10
> (s 'how-many-calls?)
1
> (s 400)
20
> (s 'how-many-calls?)
2
> (s 'reset-count)
> (s 900)
30
> (s 'how-many-calls?)
1
入力は常に適切なものが与えられると考えて良い(エラー処理を行う必要はない)。また この課題では、set!関数を利用してよい。
締切: 11/21 23:59
「stream-map」と同様の関数、すなわちストリームに対してmap操作を行う関数である「my-stream-map」を定義せよ。なお、要素がstream-nullであるか否かを判定する場合には、ライブラリで用意されているstream-null?関数を利用すればよい。
実行例:
> (define (square x) (* x x))
> (define squared_s (my-stream-map square (list->stream (list 1 2 3 4))))
> (stream-car squared_s)
1
> (stream-ref squared_s 2)
9
締切: 11/21 23:59
整数ストリームSを引数として取り、要素がS0, S0 +S1, S0 +S1 +S2, ...である 整数ストリームを返す関数である「partial-sums」を定義せよ。
実行例:
> (stream-car (partial-sums integers))
1
> (stream-ref (partial-sums integers) 3)
10
締切: 11/21 23:59
要素が全て異なりかつ昇順に並べられている2つの整数ストリームS1とS2を引数として取り、マージされた整数ストリームSを返す関数である「stream-merge」を定義せよ。ただし、整数ストリームSは要素が昇順に並べられているものとし、重複している要素は取り除かれているものとする。
実行例:
> (define merge_s (stream-merge (list->stream (list 1 2 3 4 5)) (list->stream (list 1 3 5 7 9))))
> (stream-car merge_s)
1
> (stream-ref merge_s 5)
7
締切: 11/21 23:59
3 つのストリームS, T, U を引数として取り、三つ組 (Si, Tj, Uk) のストリームを生成する関数triplesを定義せよ。ただし、 i ≤ j ≤ k とする。また、定義したtriples を用いて全ての正の整数のピタゴラス 数のストリームを生成するpythagorean-triplesを定義せよ。ここでピタゴラス数とは、 i≤jかつi2 +j2 =k2 を満たす三つ組 (i, j, k) とする。
実行例: (triplesの定義によっては、順番が違う可能性がある)
> (stream-ref pythagorean-triples 0)
(3 4 5)
> (stream-ref pythagorean-triples 2)
(5 12 13)
> (stream-ref pythagorean-triples 4)
(8 15 17)
ヒント: 一番簡単な方法としては、pairsの定義と同様、1. (S0, T0, U0)、2. S0を一つ目に持つ(S0, T0, U0)以外の全てのtriples、3. 1でも2でもない残りのtriplesという3つの構成要素から成り立っていると考える方法が上げられる。
(注: triplesが受け取るストリームの要素は整数とは限りません。整数でない要素を持つストリームに対してもtriplesが正しく動作するようにしてください。)
締切: 11/21 23:59