one?と、ふたたびrempick

one?

関数 one? は、引数が 1 のとき真、そうでないとき偽を返す。
こんなの簡単だ。

(use mymodule)

(define one?
  (lambda (n)
    (o= n 1)))

(print (one? 1))
(print (one? 10))

実行:

^o^ > gosh -I. one.scm
#t
#f

ほらできた。

ふたたび rempick

今度は、rempick を one? を使って書け、と。これも簡単、前の定義で (zero? (sub1 n)) としていたところを (one? n) にすればいいだけだ。

(use mymodule)

(define one?
  (lambda (n)
    (o= n 1)))

(define rempick
  (lambda (n lat)
    (cond
      ((one? n) (cdr lat))
      (else (cons (car lat) (rempick (sub1 n) (cdr lat)))))))

(print (rempick 3 '(lemon meringue salty pie)))

実行:

^o^ > gosh -I. rempick2.scm
(lemon meringue pie)

OK!
これで4章は終わり。

eqan?とoccur

eqan?

関数 eqan? は2つの引数が同じアトムのとき真となる関数。数に対しては=を、それ以外のアトムに対しては eq? を使って書け、と。

(use mymodule)

(define eqan?
  (lambda (a1 a2)
    (cond
      ((and (number? a1) (number? a2)) (o= a1 a2))
      ((or (number? a1) (number? a2)) #f)
      (else (eq? a1 a2)))))

(print (eqan? 3 3))
(print (eqan? 3 7))
(print (eqan? 'a 'b))
(print (eqan? 'tomato 'tomato))
(print (eqan? 1 'tomato))

実行:

^o^ > gosh -I. eqan.scm
#t
#f
#f
#t
#f

うまくいったようだ。

occur

関数 occur は lat の中にアトム a が何回現れたかを数える関数。

(use mymodule)

(define eqan?
  (lambda (a1 a2)
    (cond
      ((and (number? a1) (number? a2)) (o= a1 a2))
      ((or (number? a1) (number? a2)) #f)
      (else (eq? a1 a2)))))

(define occur
  (lambda (a lat)
    (cond
      ((null? lat) 0)
      ((eqan? (car lat) a) (add1 (occur a (cdr lat))))
      (else (occur a (cdr lat))))))

(print (occur 'cup '(coffee cup tea cup and hick cup)))

実行:

^o^ > gosh -I. occur.scm
3

こっちもうまくいった。
と思って答えを見たら、eqan? じゃなくて eq? を使ってるじゃないか。話の流れからして eqan? を使うんじゃないの?

no-numsとall-nums

number?

関数 number? は引数が数のアトムなら真で、そうでなければ偽になる。number? は Scheme では書くことができない基本関数だと紹介されている。実際、Gahche には組み込みで存在する。

gosh> (number? 5)
#t
gosh> (number? 'a)
#f

さて、今回の課題はここから。まずは no-nums。

no-nums

no-nums はラットからすべての数を取り除いたものを返す。

(define no-nums
  (lambda (lat)
    (cond
      ((null? lat) (quote ()))
      ((number? (car lat)) (no-nums (cdr lat)))
      (else (cons (car lat) (no-nums (cdr lat)))))))

(print (no-nums '(5 pears 6 prunes 9 dates)))

(number? (car lat)) が真なら (car lat) を cons せずに再帰し、そうでなければ cons して再帰している。ま、そんなに難しくない。
実行:

^o^ > gosh no-nums.scm
(pears prunes dates)

all-nums

all-nums は no-nums とは逆に、ラットからすべての数を取り出してタップを作る。
no-nums ができているんだから簡単。cons する条件を逆にするだけだ。

(define all-nums
  (lambda (lat)
    (cond
      ((null? lat) (quote ()))
      ((number? (car lat)) (cons (car lat) (all-nums (cdr lat))))
      (else (all-nums (cdr lat))))))

(print (all-nums '(5 pears 6 prunes 9 dates)))

実行:

^o^ > gosh all-nums.scm
(5 6 9)

length、pick、rempick

length

length はラットの長さを数える関数。

(use mymodule)

(define length
  (lambda (lat)
    (cond
      ((null? lat) 0)
      (else (add1 (length (cdr lat)))))))

(print (length '(hotdogs with musrard sauerkraut and pickles)))
(print (length '(ham and cheese on rye)))

実行:

^o^ > gosh -I. length.scm
6
5

pick

pick はラットの中の n 番目のアトムを返す。

(use mymodule)

(define pick
  (lambda (n lat)
    (cond
      ((zero? (sub1 n)) (car lat))
      (else (pick (sub1 n) (cdr lat))))))

(print (pick 4 '(lasagna spaghetti ravioli macaroni meatball)))

(cdr lat) で再帰するときに、同時に (sub1 n) をすることで何番目かを数えている。終了条件が (zero? (sub1 n)) なのは、インデックスが1から始まると考えているからだろう。

実行:

^o^ > gosh -I. pick.scm
macaroni

rempick

rempick は n 番目のアトムを取り除いたラットを返す。

(use mymodule)

(define rempick
  (lambda (n lat)
    (cond
      ((zero? (sub1 n)) (cdr lat))
      (else (cons (car lat) (rempick (sub1 n) (cdr lat)))))))

(print (rempick 3 '(hotdogs with hot mustard)))

実行:

^o^ > gosh -I. rempick.scm
(hotdogs with mustard)

↑と÷

変な記号の関数もこれで最後だ。

↑は累乗だ。o^と書こう。(o^ n m) は m が0になるまで1ずつ減らしながら n をかけていけばいい。

(use mymodule)

(define o^
  (lambda (n m)
    (cond
      ((zero? m) 1)
      (else (o* n (o^ n (sub1 m)))))))

(print (o^ 2 3))
(print (o^ 2 8))

実行:

^o^ > gosh -I. exp.scm
8
256

÷

次は割り算。o/ と書こう。これは関数の定義がさき出てきてしまうので素直に写経。

(use mymodule)

(define o/
  (lambda (n m)
    (cond
      ((o< n m) 0)
      (else (add1 (o/ (o- n m) m))))))

(print (o/ 9 3)) (print (o/ 10 3))

実行:

^o^ > gosh -I. quo.scm
3
3

今までの関数と違って、終了条件が zero? じゃない。この定義だとあまりは捨てられてしまう。ま、整数の割り算って、Ruby や Python でもそうか。