リストをまず
(define l1 (list 0 1 2 3 4 5 6 7 8 9))
と定義します。
次の関数を作る。 「リストを引数に取り、そのリストの要素を逆順に入れているリストを返す」 反復的なプロセスによる再帰で作れる。
(define my-reverse (lambda (l)
(define inner
(lambda (l n)
(if (null? l)
n
(inner (cdr l) (cons (car l) n))
)
)
)
(inner l '())
)
)
「述語とリストを受け取り、述語が真である要素の数を数える関数」 前回のmy-filterと似ているが、今回は数を数えるだけで良い。
(define my-counter (lambda (condition l)
(define inner
(lambda (condition l n)
(cond
((null? l) n)
((condition (car l)) (inner condition (cdr l) (+ n 1)))
(else (inner condition (cdr l) n))
)
)
)
(inner condition l 0)
)
)
「引数としてリスト(全て数値で構成)を受け取り、その3乗和を計算する関数」
考え方としてはまず(1)受け取ったリストの各要素を3乗した新たなリストを作成し、(2)リストの各要素を足し合わせるというのが手っ取り早いと思われる。
組み込みのmapとreduceを使うと便利。
だがここでは敢えてその二つから作る。
(1)各要素に何か計算を施した新たなリストを返すmy-mapの作成
詳しくは高階関数に関する記事を参照。
(define my-map
(lambda (process l)
(if (null? l)
'()
(cons (process (car l)) (my-map process (cdr l)))
)
)
)
(2)与えられたリストの各要素のcarとcdrに対して再帰的に演算を行う。
(関数 (リストcar1) (関数 (リストcar2) (関数 (リストcar3)...)))
関数は2つの値を引数に持つものである必要がある。
この関数に当たる部分を+に変えれば再帰的プロセスで総和を求めることも可能。
(define my-reduce (lambda (process initial l)
(if (null? l)
initial;これは総和を求める際は0、積の場合は1といった具合
(process (car l) (my-reduce process initial (cdr l)))
)
)
)
総和なら次の1行目、リストが連続した自然数なら階乗を求めたりもできる。
(my-reduce + 0 l1)
(my-reduce * 1 (list 1 2 3 4))
これらの関数を組み合わせたら瞬殺。
(define sum-of-pow3 (lambda (l)
(my-reduce + 0 (my-map (lambda (x) (* x x x)) l))
)
)
lambdaの書き方に慣れていればこういうときにいちいち外部に2乗するための関数を書かなくてもよくなったりする良いことがあります。
敢えてmapやreduceを自作しましたが組み込みで使えるはずなのでそっちでやったほうが速く終わります。ただ自分としても内部の確認をもう一度したかったのでわざとなるべく自作という方針でやりました。