名前つき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. 可変長の引数をとる関数