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式ってすげえ読みやすいんじゃないかって気がしてきたぜ。たぶん気のせいです。