練習問題 (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 本の練習問題をやっておきたいかな。結構面白いです。