課題の回答例


課題1-1

演算子の部分が複合式であるような式の場合、1.5節で説明
した「計算の順序」はどうなるか? 次の関数を例にとって説明せよ。

(define (a-plus-abs-b a b)
  ((if (> b 0) + -) a b))

(a-plus-abs-b (+ 1 2) (- 1 2))
という式を計算する順序で考える。

正規順序の場合、
1. (a-plus-abs-b (+ 1 2) (- 1 2))
2. ((if (> (- 1 2) 0) + -) (+ 1 2) (- 1 2)))
3. ((if (> -1      0) + -) (+ 1 2) (- 1 2)))
4. ((if False         + -) (+ 1 2) (- 1 2)))
5. (-                      (+ 1 2) (- 1 2)))
6. (-                      3       -1     ))
7. 4
という順序で、また
適用的順序の場合、
1. (a-plus-abs-b (+ 1 2) (- 1 2))
2. (a-plus-abs-b 3       -1     )
3. ((if (> -1 0) + -) 3 -1))
4. ((if False    + -) 3 -1))
5. (-                 3 -1))
6. 4
という順序で行われる。

例を見ると分かるように、a-plus-abs-b への適用の際には、計算の順序が違っ
ているが、内側の ((if ...) a b) を適用する際には、どちらも演算子(if ...)
の部分を先に計算して - に置換をしている。これは演算子が決まらない限り
置換が行えないので当然と言えば当然である。

(問題がいまいちでした。)


課題1-2

ある数 n の階乗(factorial)は、1 から n までを掛けた数である。より数
学的には、
	1          n = 0の場合
n! = {
        n・(n-1)!  それ以外
のように定義される。

この階乗を求める Scheme の関数を作れ。

> (define (factorial n)
    (if (= n 0)
	1
	(* n (factorial (- n 1)))))
;Evaluation took 0 mSec (0 in gc) 36 cells work, 47 bytes other
#<unspecified>
> (factorial 100)
;Evaluation took 0 mSec (0 in gc) 397 cells work, 2985 bytes other
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
>
(ほとんど数学的定義そのままですね。)


課題1-3

フィボナッチ数列(Fibonacci numbers)とは、
        0, 1, 1, 2, 3, 5, 8, 13, 21, ...
のように、「前 2 つの数の和」で作られる数の列である。
つまり、n 番目のフィボナッチ数は、
Fib(n) = 0			n = 0 の場合
         1			n = 1 の場合
         Fib(n-1)+Fib(n-2)	それ以外
のように定義できる。n 番目のフィボナッチ数を求める関数を Scheme で定
義せよ。ただし、定義は一種類とは限らないので、複数考え付く場合は複数個
提出してよい。

> (define (fibonacci n)
    (cond ((= n 0) 0)
	  ((= n 1) 1)
	  (else (+ (fibonacci (- n 1)) (fibonacci (- n 2))))))
;Evaluation took 0 mSec (0 in gc) 50 cells work, 43 bytes other
#<unspecified>
> (fibonacci 10)
;Evaluation took 0 mSec (0 in gc) 537 cells work, 33 bytes other
55
> (fibonacci 20)
;Evaluation took 150 mSec (33 in gc) 65677 cells work, 33 bytes other
6765
> (fibonacci 25)
;Evaluation took 1500 mSec (200 in gc) 728359 cells work, 33 bytes other
75025
>
(これはほんの一例です。)


課題1-4

ある数 n が素数かを調べる関数を定義せよ。(これも方法は一通りとは限ら
ないので、複数の定義を提出してよい。)
その際、sqrt の例にならって、複数の関数に分割して定義すること。

ヒント: (remainder m n)は、m を n で割った余りを求め
る関数である。

;; 定義1:
;; m が n で割り切れるかをテストする
(define (divisible? m n)
  (= 0 (remainder m n)))
;; m が n〜(m-1) のどの数でも割り切れないことをテストする
;;   n = m であるか、
;;	m が n で割り切れず、かつ、
;;      m が (n+1)〜(m-1) のどの数でも割り切れない
(define (not-divisible-from m n)
  (or (= m n)
      (and (not (divisible? m n))
	   (not-divisible-from m (+ n 1)))))
;; m が素数かどうかを調べる
;; つまり、m が 2〜(m-1)のどの数でも割り切れないことをテストする
(define (prime? m)
  (not-divisible-from m 2))

;; 定義2: 上の定義を、局所的な関数定義を使って書き直す
;; m が素数かどうかを調べる
;; つまり、m が 2〜(m-1)のどの数でも割り切れないことをテストする
(define (prime? m)
  ;; m が n で割り切れるかをテストする
  (define (divisible? n)
    (= 0 (remainder m n)))
  ;; m が n〜(m-1) のどの数でも割り切れないことをテストする
  ;;   n = m であるか、
  ;;	m が n で割り切れず、かつ、
  ;;      m が (n+1)〜(m-1) のどの数でも割り切れない
  (define (not-divisible-from n)
    (or (= m n)
	(and (not (divisible? n))
	     (not-divisible-from (+ n 1)))))
  (not-divisible-from 2))
> (prime? 1009)
#t
> (prime? 1011)
#f
> (prime? 1013)
#t
>