星田さんの記事へのコメント。
> 名前付きLet
慣れたら便利かもだけど・・
その通りです(笑)。
名前付きletの存在意義は「便利だから」以外に何もありません。
これはANSI Common Lispには存在しなく、某書だとマクロの例題として取り上げられてる感じですね。
事実上、後述のletrecのシンタックスシュガー(構文糖衣)です。
結果、Schemeのletは、define-syntaxで次のように定義されてる、って考えて良いでしょう。
(define-syntax my-let
(syntax-rules ()
((_ ((p v) ...) exp ...) ;; ここは普通のlet
((lambda (p ...) exp ...) v ...))
((_ name ((p v) ...) exp ...) ;; こっちは名前付きlet
(letrec ((name (lambda (p ...) exp ...)))
(name v ...)))))
> Letrec
うーん・・つまり関数の中でその関数に引数を渡せるということ?これは必要そうかな?
はい。
ただし、Schemerはどっちかっつーと、川合史朗さんのようにinternal defineを使う方を好みますね。
(define (fact-define n)
(define (iter n1 p)
(if (= n1 1)
p
(let ((m (- n1 1)))
(iter m (* p m)))))
(iter n n))
だから実際は、Schemeだと名前付きletに比べると出番があまりありません。これを使うより名前付きletを使った方が簡単になるケースの方が多いから、です(上で見た通り、事実上名前付きletはletrecの構文糖衣だから)。
ただし、こっちの方はANSI Common Lispに対応する機能があって、それをlabelsと言います。
> do
名前は聞いたことあったけど、なんかこれは面白そうじゃないか!?まあ問題はSchemeにのみ存在するような・・
いやいや、これもANSI Common Lispに入ってます。
doは汎用過ぎて、ANSI Common Lisp好きもSchemerも使用頻度は高くはないです。むしろANSI Common Lisp好きは使用目的が明快なdotimesやdolistの使用頻度が高いでしょう。
両方共doをベースにしたマクロだと考えてまぁ間違いありません。
;; dotimes(define-syntax dotimes
(syntax-rules ()
((_ (var count-form result-form) statement ...)
(do ((var 0 (+ var 1)))
((= var count-form) result-form)
statement ...))
((_ (var count-from) statement ...)
(dotimes (var count-from #f) statement ...))));; dolist(define-syntax dolist
(syntax-rules ()
((_ (var list-form result-form) statement ...)
(do ((lst list-form (cdr lst)))
((null? lst) result-form)
(let ((var (car lst)))
statement ...)))
((_ (var list-form) statement ...)
(dolist (var list-form #f) statement ...))))
ちなみに「繰り返しのdo」ってのは少々古めかしい表現です。
これは元々、世界最初の高級言語、Fortranの繰り返し構文で、世界で二番目の高級言語、LispはFortranの命名法に影響を受けています。
次回から高階関数。これは大事だろうからしっかりやろう!
頑張ってください!