練習問題 (2)
ピアソンの scheme 本の練習問題の続き。
練習問題 2.8.3 (n とオブジェクトを引数に受け取り、リストを作る手続きを作成)
こんな感じらしい。
guile> (make-list 7 '()) (() () () () () () ()) guile>
n に対するチェックは略で。
n 回繰り返せば良いからこんな感じ??
(define (make-list n o) (let f ((n n)) (if (zero? n) '() (cons o (f (- n 1))))))
あら、動いた。letrec 版も。
(define (make-list n o) (letrec ((f (lambda (n) (if (zero? n) '() (cons o (f (- n 1))))))) (f n)))
練習問題 2.8.4 (list-ref と list-tail の実装)
とりあえず標準プロシジャの挙動を。
guile> (list-ref '(a b c) 0) a guile> (list-ref '(a b c) 1) b guile> (list-ref '(a b c) 2) c guile> (list-ref '(a b c) 3) standard input:457:1: In procedure list-ref in expression (list-ref (quote #) 3): standard input:457:1: Argument 2 out of range: 3 ABORT: (out-of-range) guile> (list-tail '(a b c) 0) (a b c) guile> (list-tail '(a b c) 1) (b c) guile> (list-tail '(a b c) 2) (c) guile> (list-tail '(a b c) 3) () guile> (list-tail '(a b c . d) 2) (c . d) guile> (list-tail '(a b c . d) 3) d guile>
list-ref は指定された要素で list-tail は指定された要素以降のリスト、という理解で OK らしい。指定要素は単純な繰り返しだな。
(define (list-ref2 l n) (let f ((n n) (l l)) (if (zero? n) (car l) (f (- n 1) (cdr l)))))
動作試験。
guile> (list-ref2 '(a b c) 0) a guile> (list-ref2 '(a b c) 1) b guile> (list-ref2 '(a b c) 2) c guile> (list-ref2 '(a b c) 3) standard input:467:9: In procedure car in expression (car l): standard input:467:9: Wrong type argument in position 1: () ABORT: (wrong-type-arg) guile>
最後のエラーメセジが微妙に違うな。他の言い方がないかなぁ。とりあえず list-tail も検討。ってか引数でもらったリストを返せば良いだけ??
(define (list-tail2 l n) (let f ((l l) (n n)) (if (zero? n) l (f (cdr l) (- n 1)))))
動作試験を。
guile> (list-tail2 '(a b c) 0) (a b c) guile> (list-tail2 '(a b c) 1) (b c) guile> (list-tail2 '(a b c) 2) (c) guile> (list-tail2 '(a b c) 3) () guile> (list-tail2 '(a b c) 4) standard input:482:12: In procedure cdr in expression (cdr l): standard input:482:12: Wrong type argument in position 1: () ABORT: (wrong-type-arg) guile> (list-tail2 '(a b c . d) 2) (c . d) guile> (list-tail2 '(a b c . d) 3) d guile>
なんかワンパターンだなぁ。しゃべれてるけど、語彙が少ない感じ。
練習問題 2.8.5 (length 使わず shorter 定義)
length 使う shorter は以下。
(define (shorter n m) (cond ((< (length n) (length m)) n) (else m)))
length を自分で実装すれば良いのかな。こんな感じ?? (引数はリスト限定
(define (my-length l) (let f ((l l)) (if (null? l) 0 (+ 1 (f (cdr l))))))
てーか、あまり考えずに 0 返却でナニなのは野生の勘かなぁ。てきとーにヤッツけちゃって一応セーフな動作なのは経験値、とゆー事にしとこう (こら
それは良いとして試験を。
guile> (my-length '(a b c)) 3 guile> (my-length '()) 0 guile> (my-length '(1)) 1 guile> (my-length '(a b (c d) e)) 4 guile>
末端の葉の数の検査ではない、という勝手な判断にて上記で OK とします。上記の my-length を組み込んだ shorter は以下か。
(define (shorter n m) (cond ((< (my-length n) (my-length m)) n) (else m)))
練習問題 2.8.7 (以下のような動作をする transpose を map を使って定義)
guile> (transpose '((a . 1) (b . 2) (c . 3))) ((a b c) 1 2 3) guile>
うーむ。6.4 手続きのリスト上への写像を再読した方が良いかも。
で、資料によると (map cons '(a b c) '(1 2 3)) が ((a . 1) (b . 2) (c . 3)) になるようなコトが書いてありますな。ちなみにテキストには ((a b c) 1 2 3) は ((a b c) . (1 2 3)) と同じである、とのヒントあり。これは (cons '(a b c) '(1 2 3)) の結果である、と言っても OK なはず。
要件は_ペアのリストを受け取ってリストのペアを返却_となっている。
うーん。色々試してみよう。例えばペアのリストを map car したら??
guile> (map car '((a . 1) (b . 2) (c . 3))) (a b c) guile>
では cdr は??
guile> (map cdr '((a . 1) (b . 2) (c . 3))) (1 2 3) guile>
じゃ、これらを cons すれば出来上がりですか??
guile> ((lambda (l) (cons (map car l) (map cdr l))) '((a . 1) (b . 2) (c . 3))) ((a b c) 1 2 3) guile>
げ。出来ちゃったし。
掃除命令が出たので一旦休憩。独習 scheme 三週間の Chapter.13 に戻るまでにもう少しだけピアソン scheme 本の練習問題をやっておきたいかな。結構面白いです。