『Scheme手習い』

『7つの言語 7つの世界』を見事に積読することに成功したが、どうしてもLispへの興味が衰えないので、『Scheme手習い』をだらだら読んでいた。

内容は、Schemeを通じてひたすら再帰の考え方を身につけさせる、というもの。ただし、再帰以外にも、ラムダ計算やらSchemeインタプリタをScheme上で実装するなんて話題も出てくる。

順当に読み進めていけば詰まるようなことはないが、継続やYコンビネータといった概念が出てくるようになる第8章の後半以降から、難易度が一気に跳ね上がる。そしてもちろん、おれはこれらの概念を理解できていない。こんなんでこの先大丈夫か。

以下のコードは、色んな章で使いまわされる関数をまとめたもの。ちなみに処理系はGaucheを使用している。これらのコードをbase.scmファイルとして保存し、同じディレクトリ下の別の.scmファイルの先頭に (use base) とでも書いとけばいいはず。

(define-module base
  (export-all))
(select-module base)

;; 引数はアトムか?
(define atom?
  (lambda (x)
    (and (not (pair? x)) (not (null? x)))))

;; 要素がアトムだけのリストか?
(define lat?
  (lambda (lst)
    (cond ((null? lst) #t)
          ((atom? (car lst)) (lat? (cdr lst)))
          (else #f))))

;; 引数に1を加算
(define add1
  (lambda (n) (+ n 1)))

;; 引数に1を減算
(define sub1
  (lambda (n) (- n 1)))

;; 2つの引数は同じアトムか?
(define eqan?
  (lambda (x y)
    (cond [(and (number? x) (number? y))
           (= x y)]
          [(and (atom? x) (atom? y))
           (eq? x y)]
          (else #f))))

;; 同じS式か?
(define equal?
  (lambda (s1 s2)
    (cond [(and (atom? s1) (atom? s2))
           (eqan? s1 s2)]
          [(or (atom? s1) (atom? s2)) #f]
          (else (eqlist? s1 s2)))))

;; 同じリストか?
(define eqlist?
  (lambda (l1 l2)
    (cond [(and (null? l1) (null? l2)) #t]
          [(or (null? l1) (null? l2)) #f]
          (else (and (equal? (car l1) (car l2))
                     (eqlist? (cdr l1) (cdr l2)))))))

;; xのy乗
(define **
  (lambda (x y)
    (cond [(zero? y) 1]
          (else (* x
                   (** x (sub1 y)))))))

;; latにaは含まれるか?
(define member?
  (lambda (a lat)
    (cond [(null? lat) #f]
          [(eq? (car lat) a) #t]
          (else (member a (cdr lat))))))

;; 第一要素
(define first
  (lambda (p) (car p)))

;; 第二要素
(define second
  (lambda (p) (car (cdr p))))

;; 第三要素
(define third
  (lambda (l) (car (cdr (cdr l)))))

;; ペアではないリストを生成する
(define build
  (lambda (a1 a2)
    (cons a1
          (cons a2 '()))))

;; 2つのS式だけからなるリストか?
(define a-pair?
  (lambda (x)
    (cond [(null? x) #f]
          [(atom? x) #f]
          [(null? (cdr x)) #f]
          [(null? (cdr (cdr x))) #t]
          (else #f))))

(provide "base")