letとletrecの違いとか

自然言語でletとletrecの違いが書いてあるのを読んでもよくわからなんだ。自分で書いてみてわかった。
書いたのは与えられたリストをconsで再帰的に定義してそのまま返すだけの関数。

gosh> (let ((f (lambda (lst) (if (null? lst) '() (cons (car lst) (f (cdr lst))))))) (f '()))
()
gosh> (let ((f (lambda (lst) (if (null? lst) '() (cons (car lst) (f (cdr lst))))))) (f '(3 2 1 0)))
*** ERROR: unbound variable: f
Stack Trace:
_______________________________________
  0  (f (cdr lst))
        At line 2 of "(stdin)"

fなんて関数知らねーよ、と。一回目のf呼び出しの時にはシンボルfはletにてlambdaで定義された関数に結びつけられているから大丈夫だけど、再帰で呼び出したfはfなんて関数知らない。これが静的スコープってことか。

letで再帰させるには以下のようにさせなければいけない。

gosh> (let ((f (lambda (f lst) (if (null? lst) '() (cons (car lst) (f f (cdr lst))))))) (f f '(3 2 1 0)))
(3 2 1 0)

しんどいね。letrecを使えば以下のように書けます。

gosh> (letrec ((f (lambda (lst) (if (null? lst) '() (cons (car lst) (f (cdr lst))))))) (f '(3 2 1 0)))
(3 2 1 0)

Schemeで何ができるかなんて知ったこっちゃないけどSchemeバンザイSchemeバンザイ。っていうかS式バンザイなんかS式ってすげえ読みやすいんじゃないかって気がしてきたぜ。たぶん気のせいです。

test