HOME | 4. 関数を定義しよう | もうひとつの Scheme 入門 | 6. 局所変数 | 書き込む |
今回は処理の分岐について説明します。
(if predicate then_value else_value)predicate (述語)が真を返せば、then_value が、 そうでなければ else_value の値が評価されて括弧の外に出て行きます。 ここで、真というのは偽 (#f で表される。) 以外の値全てです。真の代表値は #t です。
Scheme では偽を表す #f と、 空リストを表す '() は別のものです。 一方、Common Lisp では、偽と空リストは同じものとして規定されています。 Common Lisp から移ってきた人は両者を混同しないよう注意する必要があります。
条件を打ち消すときは not 関数を使います。 この関数は、引数が #f なら #t を、 それ以外なら #f を返します。
if は普通の関数と違い、引数を全て評価することをしません。 predicate が真のときは then_value だけを評価し else_value は評価しません。 その逆に、predicate が偽のときは else_value だけを評価し、 then_value は評価しません。 if の様にカッコ内のトークンの全てを評価しない手続きを特殊形式と呼びます。
例:初項 a0, 公比 r, 項数 n の等比数列の和
(define (sum-gp a0 r n)
(* a0
(if (= r 1)
n
(/ (- 1 (expt r n)) (- 1 r))))) ; !!
一般に、等比数列の和は、a0 * (1 - rn) / (1 - r)
a0 * n
else_value は省略することができますが (注1)、 その場合は predicate が成り立たないとき返る値は規定されていません。 predicate が成り立たないとき #f を返したいときは、#f が返ることを明示する必要があります。
then_value, else_value も値を返す式1つだけを指定できます。
複数の式を指定したい場合には begin 式でくくる必要があります。
今のところは値を返す式だけを説明しているので、begin
を使う必要はありません。begin については代入、I/O のところで
説明します。
練習問題 1
次の関数を作ってください。条件式を作るときは 5 節を参考にして下さい。
> (and #f 0) #f > (and 1 2 3) 3 > (and 1 2 3 #f) #f
> (or #f 0) 0 > (or 1 2 3) 1 > (or #f 1 2 3) 1 > (or #f #f #f) #f
(cond (predicate_1 clauses_1) (predicate_2 clauses_2) ...... (predicate_n clauses_n) (else clauses_else))この式では、predicate_1 から順番に調べ、一致した条件式のところの節を評価します。 条件に一致しない節は評価されません。
clauses_i には複数の式を書くことができ、最後の式の値が返ってきます。 どの条件も成り立たないときは clauses_else の値が返ってきます。
(else clauses_else) を必ず書く癖をつけると、わかりにくいバグに悩まされることが減ります。
例:市営プールの料金
Foo 市の市営プールでは年齢によって料金を分けています。
(define (fee age) (cond ((or (<= age 3) (>= age 65)) 0) ((<= 4 age 6) 50) ((<= 7 age 12) 100) ((<= 13 age 15) 150) ((<= 16 age 18) 180) (else 200)))
(begin s1 s2 ... s-end)
s1, s2 ... s-end を前から順番に評価し、s-end の値を返す。
例:
(define (foo) (begin (display "hello world.") (newline) (display "I love Scheme.") (newline) 'done))"hello world"、 "I love Scheme." が表示されて、値 done が返ります。
> (foo)
hello world.
I love Scheme.
done
(when predicate
s1
s2
...
s-end )
predicate が成り立つとき、s1, s2 ... s-end を順番に評価し、s-end の値を返します。
例:
(define (foo fine) (when fine (display "hello world.") (newline) (display "It is fine, today.") (newline) 'done))
> (foo #t)
hello world.
It is fine, today.
done
(unless predicate
s1
s2
...
s-end )
predicate が成りたたないとき、s1, s2 ... s-end を順番に評価し、s-end の値を返します。
例:
(define (foo cold) (unless cold (display "hello world.") (newline) (display "It is not cold, today.") (newline) 'done))
> (foo #f)
hello world.
It is not cold, today.
done
> (define str "hello") > (eq? str str) #t > (eq? "hello" "hello") #f ;;; 数値の比較は処理系依存 > (eq? 1 1) #t > (eq? 1.0 1.0) #f
> (eqv? 1.0 1.0) #t > (eqv? 1 1.0) #f ;;; リストの比較では偽になる > (eqv? (list 1 2 3) (list 1 2 3)) #f ;;; 文字列の比較は処理系依存 (文字列の比較には equal? または string=? を使うべき ) > (eqv? "hello" "hello") #f ;;; 以下の例は処理系依存 > (eqv? (lambda(x) x) (lambda (x) x)) #f
> (equal? (list 1 2 3) (list 1 2 3)) #t > (equal? "hello" "hello") #t
> (= 1 1 1.0) #t > (< 1 2 3) #t > (< 1) #t > (<) #t > (= 2 2 2) #t > (< 2 3 3.1) #t > (> 4 1 -0.2) #t > (<= 1 1 1.1) #t > (>= 2 1 1.0) #t > (< 3 4 3.9) #f
次回は局所変数について述べます。
; 1 (define (my-abs n) (* n (if (positive? n) 1 -1))) ; 2 (define (inv n) (if (not (zero? n)) (/ n))) ; 3 (define (i2a n) (if (<= 33 n 126) (integer->char n)))
; 1 (define (pro3and a b c) (and (positive? a) (positive? b) (positive? c) (* a b c))) ; 2 (define (pro3or a b c) (if (or (negative? a) (negative? b) (negative? c)) (* a b c)))
(define (score n) (cond ((>= n 80) 'A) ((<= 60 n 79) 'B) ((<= 40 n 59) 'C) (else 'D)))
HOME | 4. 関数を定義しよう | もうひとつの Scheme 入門 | 6. 局所変数 | 書き込む |