2009年1月30日金曜日

schemeでラムダ式をちょろっと勉強する

最近ちょこちょこschemeの勉強をしてる。
以下のコードなんだけど。

リスト ls から指定した値 x を除去する関数 remove-x

(define (remove-x x ls)
(if (null? ls)
'()
(let ((h (car ls))) ; ls のheadの値をhに束縛
(if (eqv? x h) ; 引数xとhは同じ値か?
(remove-x x (cdr ls)) ; 同じならlsのtailを引数にして再帰
(cons h (remove-x x (cdr ls))) ; 違うならhを再帰処理の結果と結合する
))))

上の例だと再帰関数であるremove-xを,if文の結果がtrueのときとfalseのときとで2回書く必要がある。これをラムダ式を使うと、以下のように書き換えることができる。

(define (remove-x x ls)
(if (null? ls)
'()
(let ((h (car ls)))
((if (eqv? x h)
(lambda (y) y)
(lambda (y) (cons h y)))
(remove-x x (cdr ls)) ;; ラムダ関数の引数yに束縛する関数
))))

こう書くことで (remove-x x (cdr ls)) がラムダ関数の手続き中の変数 y のところで展開され、処理としては最初に示したコードと同じになる。再帰関数の記述の箇所が1箇所で済むようになった。

ラムダ式、おもしろっ。

schemeのレキシカルクロージャとかラムダ式とかが何となく分かった気がしてくると、これまで今いち掴めなかったJavasScriptについても何だか腑に落ちてきた気がする。anonymous関数とかね。

2 件のコメント:

Takeo Kunishima さんのコメント...

ちなみにStandard MLでも同じようなことはできるよ。講義で話さなかったカリー化関数というのを使うと、こんな感じになるかな。

fun removex n nil = nil
| removex n (x::xs) =
(if n=x then (fn y => y)
else (fn y => (x::y))) (removex n xs);

Connie さんのコメント...

コメントありがとう御座います。
SMLだとカリー化関数って言うんですね。
勉強になります。