名前つきlet の練習。
cf. 7. 繰り返し – もうひとつの Scheme 入門
の練習問題3より。
my-delete
リスト (ls) から要素 (x) を取り除いたリストを返す関数。
(define my-delete
(lambda (x ls)
(let loop ((y x) (l1 ls) (l2 '()))
(if (null? l1)
(reverse l2)
(loop y (cdr l1) (if (eq? y (car l1))
l2
(cons (car l1) l2)))))))
(print (my-delete 'c '(a b c d e)))
^o^ > gosh my-delete3.scm
(a b d e)
この関数は下のように素直な再帰のほうがわかりやすいけど、代わりに末尾再帰にならない。
(define my-delete
(lambda (x ls)
(cond
((null? ls) '())
((eq? x (car ls)) (my-delete x (cdr ls)))
(else (cons (car ls) (my-delete x (cdr ls)))))))
index
リスト (ls) の要素 (x) の位置を返す関数。位置は 0 から数え始め、 x がない場合は #f を返す。
(define index
(lambda (x ls)
(let loop ((y x) (l ls) (n 0))
(cond
((null? l) #f)
((eq? y (car l)) n)
(else (loop y (cdr l) (+ n 1)))))))
(print (index 'c '(a b c d e)))
(print (index 'f '(a b c d e)))
^o^ > gosh index2.scm
2
#f
sum
数のリストの要素の合計を求める関数。
(define sum
(lambda (lis)
(let loop ((l lis) (s 0))
(if (null? l)
s
(loop (cdr l) (+ s (car l)))))))
(print (sum '(1 2 3 4 5)))
^o^ > gosh sum.scm
15
string->integer
正の整数を表す文字列を整数に変関する関数。入力エラーチェックはしなくて良い。
例: “1232” → 1232
ヒント:
- 文字 #\0 … #\9 のASCII コード番号から 48 を引くとその数そのものになります。 アスキーコードを求める関数は char->integer です。
- 文字列を文字のリストに変換する関数 string->list を使うと便利です。
(define string->integer
(lambda (str)
(let loop ((ls (string->list str)) (i 0))
(if (null? ls)
i
(loop (cdr ls) (+ (* i 10) (- (char->integer (car ls)) 48)))))))
(print (string->integer "1234"))
^o^ > gosh string-to-integer.scm
1234
range
0 から n 未満の整数のリストを返す関数。
(define range
(lambda (n)
(let loop ((m (- n 1)) (l '()))
(if (< m 0)
l
(loop (- m 1) (cons m l))))))
(print (range 10))
^o^ > gosh range.scm
(0 1 2 3 4 5 6 7 8 9)
ave
任意個の引数をとりそれらの平均を返す関数。レストパラメータを使う。全ての引数は数、エラー処理は不要。
(define ave
(lambda ls
(let loop ((l ls) (s 0) (n (length ls)))
(if (null? l)
(/ s n)
(loop (cdr l) (+ s (car l)) n)))))
(print (ave 1.1 2.3 4.6))
(print (ave 3.3 4.7 10.2 20.6 100.1))
^o^ > gosh ave.scm
2.6666666666666665
27.779999999999994
(lambda ls ...)
という書き方で、0個以上の引数をとりすべて ls にリストとして束縛される。以下も参照。
cf. 可変長の引数をとる関数