2008年07月28日 10:00 [Edit]
LLからCL? - 書評 - 実践Common Lisp
共訳者の佐野様より献本御礼。
なんでこういう Common Lisp 本がなかったかという、さまざまな意味で21世紀的な Lisp本。LL、特に「P言語」の読者は必読。CLに走るせよ、LLに留まるにせよ。
本書「実践Common Lisp」は、英文学科(と便宜的に訳すが、ずばりEnglish)を卒業してジャーナリストとなった後、Perlプログラマー、Javaプログラマーを経てCommon Lispプログラマーとなった異色の「第二世代 Common Lisper」である著者が、「P言語」(perl/python/ruby)およびJavaプログラマーに向けて書いたCommon Lisp入門の邦訳。原文はWeb公開もされている。
目次 - Ohmshaより
|
|
本書を読んで最も驚くのは、むしろ「P言語」やJavaの使い手ではなく、schemerではなかろうか。その違いは、目次を見ただけで伺い知ることが出来る。せっかくなので「プログラミングGauce」のそれと比べて見よう。
目次 - 404 Blog Not Found:(use gauche); 書評 - プログラミングGaucheより
|
|
|
一目見てわかるのは、「プログラミングGauche」では第三部になってやっと登場するマクロが、いきなりのっけから登場することである。その代わり、Lispのイロハのイであるはずのリストに関する言及は、第12章にやっと登場するのだ。
コードもまた違う。Schemeを特徴づける再帰は、本書ではほとんど見られない。その代わり本書でびしばし登場するのが、マクロである。実際に定義もするのだが、それよりも多様な標準装備のマクロの多用が目立つ。その中でも際立って目立つのがloopマクロの多用だ。おそらく本書に登場する述語(predicate)の中で最も多いのではないだろうか。
Schemerなら、のんびりと
(define (from-to from to) (if (> from to) '() (cons from (from-to (+ from 1) to)))) (from-to 1 10)
とするか、あるいは華麗に
(use srfi-1) ; gaucheなら (iota 10 1)
とするかという感じになるかと思うのだが、本書では
(loop for i from 1 to 10 collecting i)
である。lispというよりはPythonやHaskellの内包表記だ。もし本書がオライリーから上梓されていたら、表紙は同じ魚でもフムフムヌクヌクアプアアどころかバラキューダだったのではないか。
本書で最も評価したのは、著者がLL言語に対して「アウェイ戦」を挑んでいること。本書には Common Lisp コードだけではなく、要所要所に Perl や Python や Java のコードが登場する。Lisperというと仙人という印象がどうもあるが、本書には肉感がある。Matz的に言えば「血が滴るような」あの感じである。
こういうガチな一冊が、欲しかった。ガチなプログラマーであれば、必ず手応えを得ることができるだろう。
で、ここからは私見。
それでもなお、いやだからこそ、Lispが実践の場で多数を占めることはないだろう。私はかつてそれはLispersの選民思想によるものだと考えていたが、本書を読了して、また「フムフムヌクヌクアプアア本」をはじめ他の本も「つられ読み」して、どうもそうではない、少なくともそれだけではないと実感した。それを実感したのは、本書でCLOSのおさらいをしていたときだ。
Lispは、その構造上、オブジェクト指向は極められても、オブジェクト思考には向かないのだ。なぜか。述語が必ずリストの頭となるからだ。
Lisp と LL の関係について - 黎明日記もしそれを望むならば、こんなふうにも書ける :(define-class <cat> (<class>) ()) (define-class <dog> (<class>) ()) (define-class <x> () () :metaclass <cat>) (define-class <y> () () :metaclass <dog>) (define-method speak ((_ <cat>)) (print "meow!")) (define-method speak ((_ <dog>)) (print "woof!")) (for-each speak (list <x> <y>))これが出来る言語はかなり限られているだろう。
ところがPerl 5にもわけなくできる。
Run via CodePad
#!/usr/local/bin/perl
use strict;
use warnings;
{
package Animal;
sub new { bless {}, shift }
package Cat;
use base 'Animal'; # inherits new()
sub speak { print "meow!\n" }
package Dog;
use base 'Animal'; # inherits new()
sub speak { print "woof!\n" }
}
$_->speak for map { $_->new } qw/Cat Dog/;
speak $_ for map { new $_ } qw/Cat Dog/;
そしてこの点が重要なのだが、Perl 5ではmethod $objectとCLOSのようにも書けるし、$object->methodとその他大勢の、OOP言語のほとんどが採用している、目的語=objectを書いてその後ろに述語=methodを書くというやり方の双方が使える。
で、どちらが推奨かといえば、双方の書き方が出来るPerlでもやはり後者の方なのだ。
オブジェクト指向を採用する理由は多々あるが、「まず対象を決めて、それから何をするかを決める」というオブジェクト思考をそのまま実践するという理由は、心理的には最大の要因だと思われる。「まず対象を決める」、これがあるからこそさほどの手だれでなくともメソッドチェインを書けるのだ。
本書で実は一番残念だったのは、著者が明らかにRubyを知らないこと。「P言語」の一つとして言及はされているのだが、言及のみで対比コードは登場しない。Rubyを知っていたら、マクロ相当の機能の欠如はまさに格好の売り文句となっていたのに。これはPythonも同様なのだが、Pythonに関しては"There is only one way to do it"ということが売り文句になっており、本書もそのことをきちんと指摘している。ちなみにPerl 5はuseがあるので、Lispのマクロ相当のことは相当できるし実際に行われている。Perlのオブジェクトシステムそのものが実は総称関数をベースとしたものだし、MOPもきちんと存在する。Mooseはその格好の事例である。
本書を読んで、Perl 5 がその実装においていかに Common Lisp に近いかを改めて実感した。dynamic scope と lexical scope の使い分け。総称関数によるOOPの実装。そしてマクロ実装の装置としてのuse....Perl 5こそ、幻のM式の実装例であり、そして Perl 6 がそれを完成させる....とは言い過ぎだろうか。
S式の最大の弱点は、括弧ではない。述語の位置が常に頭にあることなのだ。しかし同時にこれはS式の最大の利点でもあるのだ。構文木の直接表記は、強力かつ簡潔なマクロを可能とした。しかし1 + 1と書きたいのが、そしてobj.methodと書きたいのが自然人でもあるのだ。
しかし、Lispには出家を誘うだけの魅力があり、そしてCommon Lispには出家しても飢え死にしないだけのものがあるというのは、本書からびしばし伝わってくる。Lispは肉体言語でもあったのか....
`(dan the ,@language programmer)
追記:なぜforthはもっと普及しなかったのだろう。これまた述語の位置が変えられなかったからだろう....
この記事へのトラックバックURL
http://www.lisp.org/HyperSpec/Body/glo_o.html#operator
http://www.lisp.org/HyperSpec/Body/glo_p.html#predicate

