理系学生日記

おまえはいつまで学生気分なのか

問題 3-74 (3.5.3 Exploiting the Stream Paradigm)

電気でも何でも良いんですけど,信号が[負の数->正の数] と遷移したときに 1,[正の数->負の数]と遷移したときに -1,その他の遷移のときに 0 を返すような "信号" を作成する問題です.
直感的に書けば,Alyssa が書いた以下のもので OK なんですが,

(define (make-zero-crossings input-stream last-value)
  (cons-stream
   (sign-change-detector (stream-car input-stream) last-value)
   (make-zero-crossings (stream-cdr input-stream)
                        (stream-car input-stream))))

(define zero-crossings (make-zero-crossings sense-data 0))

Eva Lu Ator は stream-map を使ったもっとスマートな書き方があるとかなんとか言っていますので,それを作りましょう!


sign-change-detector は前の信号値と現在の信号値を比べて,-1, 1, 0 のどれかを返す関数.

(define (sign-change-detector cur prev)
  (cond ((and (< prev 0) (>= cur 0)) 1)
        ((and (>= prev 0) (< cur 0)) -1)
        (else 0)))

これを用いて,スマートな出力信号を作ります.stream-map というのは第二引数以降に任意個の引数を取ることができます.これらの引数は普通ストリームとかで,それぞれのストリームの先頭要素がリストとして sign-change-detector に渡される形になる.sign-change-detector は現在の値と過去の値を引数として受け取るので,stream-map に渡すストリームとして,現在の値を意味するストリーム (下記の例だと sense-data) と,過去の値を意味するストリーム ((cons-stream 0 sense-data):時間を sense-data とずらすために,0 を先頭に挿入している) を用意すれば良さそうです.

(define zero-crossing
  (stream-map sign-change-detector sense-data (cons-stream 0 sense-data)))