2010/02/08

9LISP - 009

9LISP の 009 回目を開催してきました。

午前中は9LISP、午後はKPFの第五回という楽しい一日でした。
内容はshunsukさんのこちらの記事をどうぞ。
9LISP では引き続きThe Little Schemerをテキストとして使用しています。
今回からはテキストを頭から順に進めていくスタイルを止めて、下記ポイントに絞って進めていくことになりました。
The Little Schemerでは末尾再帰とマクロについては扱われていませんし、継続渡しスタイル(CPS)の例も複雑で、正直わかりづらいです。
この辺はまたそのうち検討するということで。

継続についてはThe Little Schemerの続きであるThe Seasoned Schemerでページを割いてあるのでそちらも検討してみます。

今回は高階関数の例題を書いてみよー!ということでやってみました。
9LISP の参加者には高階関数やクロージャってなんぞ?な人から、息をするように使う人までいろんな人が参加しています。

高階関数やクロージャというのは、「概念そのものより説明することの方が難しい」という話が前回も出ていました。その点で「値渡しと参照渡し」とか「ポインタ」に似てるよねーと。たぶん継続もそうなんだろうね、ということでした。

ということで、説明うんぬんより実践あるのみということで以下の例題をやりました。
  1. 指定した要素をlistから削除するrember関数を定義する(つまりsrif-1のfilterのような関数)。
  2. list内に要素oldが存在した場合、その隣に要素newを挿入するinsert関数を定義する(挿入位置をパラメータの関数に任せる)。
実際にはまず非高階な関数を定義して、高階関数に書き換えてみる、という手順で進めました。
The Little Schemerの流れと同じです。
rember(非高階)


(define rember
  (lambda (a lat)
    (cond
     ((null? lat) lat)
     ((eq? a (car lat))(cdr lat))
     (else (cons (car lat)
                 (rember a (cdr lat))))))) 
multirember(非高階)

 (define multirember

  (lambda (a lat)
    (cond ((null? lat) lat)
          ((eq? a (car lat)) (multirember a (cdr lat)))
          (else (cons (car lat)(multirember a (cdr lat)))))))
rember*(非高階)

 (define rember*

  (lambda (a l)
    (cond ((null? l) l)
          ((atom? (car l)) (cond ((eq? a (car l))(rember* a (cdr l)))
                                 (else (cons (car l)(rember* a (cdr l))))))
          (else (cons (rember* a (car l))
                      (rember* a (cdr l)))))))
rember-f(高階)

 (define rember-f

  (lambda (test? a l)
    (cond ((null? l) l)
          ((test? a (car l)) (rember-f test? a (cdr l)))
          (else (cons (car l)
                      (rember-f test? a (cdr l)))))))
rember-f(高階)

 (define rember-f

  (lambda (test?)
    (lambda (a l)
      (cond ((null? l) l)
            ((test? a (car l))((rember-f test?) a (cdr l)))
            (else (cons (car l)
                        ((rember-f test?) a (cdr l))))))))
multirember-f(高階)

 (define multirember-f

  (lambda (test?)
    (lambda (a lat)
      (cond ((null? lat) lat)
            ((test? a (car lat))((multirember-f test?) a (cdr lat)))
            (else (cons (car lat)
                        ((multirember-f test?) a (cdr lat))))))))
というような流れです。2のinsertも同じように。

2のinsertの方は、The Little Schemerでは以下のような解答となっています。

 (define insert-g

  (lambda (seq)
    (lambda (new old l)
      (cond ((null? l) l)
            ((eq? old (car l))(seq new old (cdr l)))
            (else (cons (car l)
                        ((insert-g seq) new old (cdr l))))))))
参加者の方からも「冗長だよねー。」とか「きっともっとスマートに書けるはずだよねー、でもどう書いたらスマートだろう?」というような声がありました。

私もそう思います。ということで、考えて書いてみましたが、こんなんでどうでしょうか。srfi-1のfold-rightを使用しています・・・。


(define insert-g
  (lambda (set-f)
    (lambda (new old lat)
      (fold-right (lambda (e l)
                    (cond ((eq? old e)(set-f new old l))
                          (else (cons e l))))
                  '()
                  lat))))

ところd、foldって言語によってfold, reduce, inject, aggregateというように呼び名が違うらしいですね。

The Little Schemer, 4th EditionThe Seasoned Schemer

0 件のコメント:

コメントを投稿