Archive for 2010年6月15日|Daily archive page

newLISP で On Lisp する。。。第1章

(この blog は、“short short story または 晴耕雨読な日々”からの引越してきたもの。スクリプトは、newLISP V10.2.1 以降で動作するように書き直しています。)
(”On newLISP” は、“On Lisp”のスクリプトを newLISP で実装してみようという、試みです。経緯は、こちらでどうぞ。)

On Lisp” は説明するまでもなく、Paul Graham氏の名著です。私はこれを読んで Lisp を始めました。私が持っているのは、野田開氏訳の日本語翻訳本(ISBN978-4-274-06637-5)です。Web上で見ることが出来ますが、願わくば、購入されますように。それだけの価値はあります。

では、“第1章 拡張可能なプログラミング言語”から。特に断らない限り、CommonLisp の動作は、xyzzy での動作です。
“Lispの拡張” にあるスクリプトは、Common Lispにとっては、特に目新しいスクリプトはありません。

; スクリプト1
(mapcar fn
        (do* ((x 1 (1+ x))
              (result (list x) (push x result)))
          ((= x 10) (nreverse result))))

しかし、newLISP にとっては、厄介なスクリプトです。do* がありませんからね。いきなり大物マクロを組まなくてはいけません。
その前に、注意点。newLISP では、fn は組込関数です。Arc のように、lambda と同じ機能です。newLISP では、mapcar は map に、nreverse は reverse に相当します。関数1+ もありませんので、関数i+ を用意します。’i+’ なのは、関数や変数に ‘1+’ という名前が使えないこと。これは仕様なのでしかたありません。
前置きはさておき、do* の実装です。xyzzy reference.chm の do* 項を参考に作りました。

; スクリプト2
(define-macro (do*)
  (letex (_init (map (hayashi slice 0 2) (args 0))
          _steps (cons 'setq (flat1 (map (hayashi select '(0 2)) (args 0))))
          _results (cons 'begin (rest (args 1)))
          _end-test (first (args 1))
          _body (cons 'begin (2 (args))))
   (letn _init
     (until _end-test
       _body
       _steps)
     _results)))

中ほどの letn は、Common Lisp では、let* に相当します。これを let に変え、newLISP 版 psetq を用意すれば、do のマクロになります。その、実装例は、こちらにありますhayashiflat1 は拙作です。newlisp-utility.lsp に定義してあります。
先ほどの、注意点を含めスクリプト1を newLISP 用に書き直すと、

; スクリプト3
(define mapcar map)
(define nreverse reverse)
(define (i+ x) (+ 1 x))
(mapcar fn
        (do* ((x 1 (i+ x))
              (result (list x) (push x result)))
          ((= x 10) (nreverse result))))

これで、動きます。
(i+ は、newlisp-utility.lspで macro定義してあります。newlisp-utility.lsp を先にロードしている場合は、i+ の定義をコメント・アウトして下さい。)
実際動作させてみると、

> [cmd]
(define mapcar map)
(define nreverse reverse)
(define (i+ x) (+ 1 x))
(mapcar (fn (x) (* 2 x))
        (do* ((x 1 (i+ x))
              (result (list x) (push x result)))
          ((= x 10) (nreverse result))))
[/cmd]
(2 4 6 8 10 12 14 16 18 20)
>

さて残り、map1-n は、第4章で実装する予定です。
for は、newLISP 標準関数なので、実装しないかも(笑)。
実のところ、数字の 1 から 10 までのリストを作るだけなら、newLISP では 組込sequence を使えば、一発で済みます。

> (sequence 1 10)
(1 2 3 4 5 6 7 8 9 10)

つまり、map1-n の実装は超簡単(笑)。
ということで、今日のまとめです。

一番の問題は、最後の項目でしょうか。私にとっては、致命的でないですけどね。
さて、newLISP が、第1章のタイトル “拡張可能なプログラミング言語” であることは、間違いのないところ。そして、章の最後の問いは、“いつ Lispか?” 。ということで、この blog の締めには、次の問いを。

いつ newLISPか?

私のお薦めは、こうです。

newLISP V.10.2.8 から

以上、如何でしょうか?