Edited at

SICP読書録 #22 2.2.1(続き)リストに対するマップ - 練習問題 2.23

hiroshi-manabe様の日本語訳を使わせてもらいます。

練習問題等はGaucheで実行。

前回はこちら


リストに対するマップ

リストの全要素に指定した係数を掛けるという手続き。


_.scm

(define nil ())

(define (scale-list items factor)
(if (null? items)
nil
(cons (* (car items) factor)
(scale-list (cdr items) factor))))



_.scm

gosh> (scale-list (list 1 2 3 4 5) 10)

(10 20 30 40 50)

リストの全要素に何かをする、という抽象的な手続きmapを作ってみよう。


_.scm

(define (map proc items)

(if (null? items)
nil
(cons (proc (car items))
(map proc (cdr items)))))

mapを使えば、scale-list手続きは次のように書き直せる。


_.scm

(define (scale-list items factor)

(map (lambda (x) (* x factor)) items))


練習問題2.21

リストの要素を2乗する手続きを作ろう。まずはmapを使わずに。


_.scm

(define (square-list1 items)

(if (null? items)
nil
(cons (square (car items)) (square-list (cdr items)))))

続いて、mapを使う方法。


_.scm

(define (square-list2 items)

(map (lambda (x) (square x)) items))

動かしてみよう。


_.scm

gosh> (square-list1 (list 1 2 3 4 5))

(1 4 9 16 25)
gosh> (square-list2 (list 1 2 3 4 5))
(1 4 9 16 25)


練習問題 2.22

square-lit手続きを反復プロセス化したつもり。


_.scm

(define (square-list items)

(define (iter things answer)
(if (null? things)
answer
(iter (cdr things)
(cons (square (car things)) answer))))
(iter items nil))

動かしてみよう・・・あれれ?


_.scm

gosh> (square-list (list 1 2 3))

(9 4 1)

逆になるのも当然だ。次のように結果のリストが作られるからだ。


_.scm

> (cons (square 1) nil)    => (1)

> (cons (square 2) '(1)) => (4 1)
> (cons (square 3) '(4 1)) => (9 4 1)

ならば、こうだ。consの引数を逆にしてみる。


_.scm

(define (square-list-fix items)

(define (iter things answer)
(if (null? things)
answer
(iter (cdr things)
(cons answer (square (car things))))))
(iter items nil))

動かしてみよう。


_.scm

gosh> (square-list-fix (list 1 2 3))

(((() . 1) . 4) . 9)

ダメかー。そりゃそうだ。次のことが行われる。


_.scm

> (cons nil (square 1))             => (() . 1)

> (cons '(() . 1) (square 2)) => ((() . 1) . 4)
> (cons '((() . 1) . 4) (square 3)) => (((() . 1) . 4) . 9)


練習問題 2.23

手続きをそれぞれの要素に適用していくだけの手続きfor-eachを作ろう。begin使ってもいいよね・・・


_.scm

(define (for-each proc items)

(if (null? items)
#t
(begin
(proc (car items))
(for-each proc (cdr items)))))

実行結果。


_.scm

gosh> (for-each

(lambda (x) (newline) (display x))
(list 57 321 88))

57
321
88#t