『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")