上巻を出版しました.興味のあるかたはこちらからお願いします.

Common Lisp と人工知能プログラミングの本を執筆中ですまだ Common Lisp の部分の半分ほどしかできていませんが,およそ以下のような内容になるはずです. ほぼ完了しつつあります.出版前講演として3回にわたって「Common Lisp と 人工知能プログラミング」の第1部 Common Lisp プログラミングについて講習会を行います.
何かコメントをいただければ,できるだけ反映いたします.

目次

第1部

序章 はじめに

第1章 Lispの基本

  1.1 リストを入力してみよう
  1.2 書式を評価する
  1.3 car と cdr はリストを分解する
  1.4 シンボルは値を持つことができる
  1.5 consはリストを合成する
  1.6 便利なリスト処理関数
  1.7 数,整数,浮動小数点数,有理数

第2章 関数定義および述語と条件文

  2.1 関数定義の書式
  2.2 述語
  2.3 論理結合演算
  2.4 条件文

第3章 再帰プログラムを組む

  3.1 リストの横方向に再帰処理する
  3.2 リストの縦方向にも再帰処理する

第4章 変数束縛,動的変数,大域変数

  4.1 let 変数束縛
  4.2 特殊変数と動的スコープ
  4.3 defvar, defparameter, defconstant

第5章 Lispの内幕

  5.1 consセル
  5.2 rplaca,rplacd,そして nconc

第6章 高階関数とMAP関数

  6.1 関数は第1級のクラス
  6.2 lambda 式再び
  6.3 MAP 関数
  6.4 その他のMAP関数

第7章 マクロを書く

  7.1 マクロ展開
  7.2 バッククォート・テンプレート

第8章 コンパイラ

  8.1 eval-when で評価時期のコントロール

第9章 Lispの型システム

第10章 配列,文字列,シーケンス

第11章 Lispで作るScheme

第12章 CLOSとメタオブジェクト・プロトコル

第13章 Formatの呪文

第14章 Loopの呪文

第15章 パッケージとモジュール

  15.1 条件付き読み込み

付録1 Allegro Express のインストール

付録2 SBCL のインストール

  Debian にパッケージとしてインストール
  SBCL ライブラリ sb-aclrepl を要求する
  ライブラリマネージャ quicklisp を利用する
  開発環境 emacs+slime+sbcl

第2部

第16章 人工知能プログラミング環境

第17章 Elizaまたの名を人工無脳

  17.1 PAIP の eliza1.lisp をロードする
  17.5 Eliza のロード

第18章 一般問題解決器

第19章 探索

第20章 フレームシステム

第21章 ルールベースシステム

第22章 事例推論

第23章 ユニフィケーション

第24章 述語論理

第25章 プラニング

第26章 Lispで作るProlog

終章 おわりに


以下は序章の原稿です.


LISP は冗談に「計算機を誤用するための最も賢い方法」であるといわれてきた.この描写は大変な賛辞であると私は思う.この言葉によってLISPの持つ完全に自由な雰囲気が伝わってくるからである.――― LISP は,我々の最も才能のある人々が,以前は不可能であった試行を行う手助けをしてきたのである.[Dijkstra, 1972](人工知能プログラミング,白井・片桐訳)


なぜ Common Lisp か?

この書籍では,Common Lisp を用いて人工知能プログラミングの基礎から簡単な応用までを学ぶ.なぜ人工知能プログラミングに Common Lisp かといえば,それが人工知能を学ぶのに最適な計算機言語だからである.そもそも人工知能という言葉が生まれたのは,1956年に米国ダートマス大学で行われた会議と言われているが,そこで John McCarthy は IPL という言語で書かれた Logic Theorist というはじめての人工知能プログラムを見た.それがきっかけで,McCarthy が IPL と似た人工知能用の言語を学生と一緒に開発したのが Lisp である.その後,米国では主に Lisp をベースに,多くの人工知能システムが開発され,コミュニティに広がっていったが,インターネットの発達につれてそれらのプログラムがアノニマスFTPによって公開されるようになった.そのあたりの事情は著者の2009年発行の人工知能学会誌記事「人工知能用言語Lispの今と将来」に詳しいが,いずれにしてもその結果,1980年代に出版された多くの人工知能の教科書で,Lisp によるプログラムコードが掲載された.当時産業界におけるAIブームを目前にしていたが,商業化直前のソフトウェアの著作権についてあまりうるさくなかった時代のことである.そういうわけで,今日でも人工知能のプログラムコードを何か参照しようとすると,圧倒的に Lisp で書かれたものが多く,実際に動く人工知能システムを作ろうとすれば,Lisp を学ぶのが一番手っ取り早く,便利なのである.

Lisp が人工知能プログラミングに向いている理由は,上記のような歴史的理由だけではない.工業製品としてのプログラムを産出するプログラミングにおいては,最初に要求仕様を確定し,次にシステム仕様を定めてからプログラミングを行うが,人工知能研究ではそれとは異なり,研究者が色々なアイデアをプログラムで実現しようと,試行錯誤的にプログラミングを行う.これを探索的プログラミングと言うが,そこで計算機言語に要求される基本的な性能は,研究者の思考を妨げないこと,やろうと思うことは計算機上でなんでも実現できるような,柔軟でかつ研究者の思考をパワーアップするようなものであることである.松岡正剛氏は言う.「高級言語(プログラミング言語)にはいろいろのものがある.[...] これらの言語の特徴は大きくは,プログラマーの愚かな行為を防ぐような言語と,プログラマーがやりたいことを何でもできるようにする言語とに分かれる.」まさに慧眼である.愚かなプログラマーでも馬鹿なことをさせないようにする言語がJavaであり,賢いプログラマーに何でもできるようにする言語が Lisp なのである.

現在でも最も包括的な人工知能プログラミングの教科書である "Paradigms of Artificial Intelligence Programming" (頭文字をとって俗にPAIP,パイプと呼ばれる)の中で,著者である Peter Norvig は「何が Lisp を他の言語と違うようにしたのか?」として,Lisp の特徴を,次のように挙げた.

  • 組込みのリスト処理
  • 自動メモリ管理
  • 動的型付け
  • 第1級の関数
  • 一様な構文
  • 対話的環境
  • 拡張性
  • 歴史

リストは Lisp 生来のデータ構造であり,レンガを組み合わせて作られる建物のように,Lisp システムはセルとポインタからなるリストを基礎にできている.人工知能分野では,データはグラフ構造やツリー構造であることが多いが,これらの複雑なデータ構造もリストによって実現される.自動メモリ管理とはガーベジコレクションのことであるが,Lisp は最初からガーベジコレクションありきで設計され,当初からプログラマーがメモリ管理という仕事にわずらわされることはなかった.また,今では Lisp にも整数,浮動小数点数,配列,文字列,ハッシュなど,色々なデータ型が備えられているが,Lisp では型は変数につくのではなくデータにつく.そして変数にはどんな型のデータでもセットすることができる.Lisp は関数型言語であるが,Lisp 関数は関数に与える引数になり得る.関数を引数とする関数は高階関数と呼ばれるが,それによりプログラムを抽象化してコンパクトで理解しやすいプログラムコードにすることができる.Lisp の構文はものすごく単純である.最低限必要とする構文はリストであり,その最初の要素が関数でその他はその関数の引数になるということだけである.また,関数本体のコードもリスト構造をしており,Lisp のデータもリスト構造なので,プログラムがプログラムを生成して実行するというコードが簡単に書ける.Lisp のマクロ機能は他の言語には見られないほど高度である.Lisp のプログラムは関数の集合であるが,そのプログラミングスタイルは,対話的環境の中で短いコードを関数として定義し,それを実行・デバッグするというサイクルを早く回していくというものであった.要するにこれらの特徴すべてが,プログラマーに自由を保証し,計画なしの試行錯誤をプログラミングにおいて可能にしたのである.絵を書くときキャンバスにどのように絵を書くか計画的で学生時代に比較的よい成績を収める学生は,その後伸びないと聞くが,芸術における真の創造性は試行錯誤の中からしか生まれないとすれば,同様に,Lisp はプログラミングにおいて創造的プログラミングを最大限可能にする言語なのである.

誰がこの本を読むのか?

この書籍は,実際にこれから人工知能のプログラミング方法を習得しようとする人を対象に書かれている.人工知能は言うに及ばず,計算言語や Lisp によるプログラミングの経験を何ら前提とせず,Common Lisp プログラミングの初歩から初めて,一人前の AI プログラマーと言えるようになることを目標としている.ただし,次章以降の内容を読み進めるにあたって,どうしても Common Lisp の処理系を手元に用意することが必要であり,PC や Linux についてパッケージプログラムをダウンロードしてインストールしたり,ファイルを操作したりする程度のスキルは前提としている.Lisp の発明者である McCarthy も言うように,Lisp のプログラミングは2週間ほどで学べるが,既存の imperative な計算機言語に慣れた人ほど,かえってそれが邪魔になって習得に時間がかかる傾向がある.C++にどっぷりつかった人は一度頭をまっさらにして本書を読み進めるよう注意されたい.

なぜこの本が必要なのか?

現在入手可能な人工知能プログラミングの教科書は,ほとんどが Common Lisp 以前の Lisp で書かれたものであり,唯一 PAIP のみが Common Lisp ではあるが,それも "Common Lisp the Language" 第1版 (CLtL1) である.つまり,"Common Lisp the Language" 第2版や ANSI Common Lisp に準拠して今日 AIプログラミングの教科書として右から左にすぐ通用するものは,英語まで含めてもこの本以外にはないという状況である.

どの Common Lisp 処理系を使うのか?

現在 Common Lisp 処理系として,複数の処理系が入手可能であるが,ここでは Allegro Common Lisp (ACL) と Steel Bank Common Lisp (SBCL) を前提として話を進める.ACL は商用の Common Lisp であり,本格的なアプリ開発には商用版を購入する必要があるが,日本に販売代理店もあることから,大学・研究機関や企業で利用するには便利である.読者が本書籍の内容を学ぶにためは,開発元の Franz 社から無料の ACL Express をダウンロードして利用することができる.一方,SBCL はもともとフリーなオープンソースの Common Lisp 処理系であり,Linux や PC に容易にインストールして利用することができる.どちらをインストールしたらよいか分からない,あるいはどちらでもよいという方には,ここでは ACL Express をお勧めする.どちらかといえば ACL は初心者にやさしく,SBCL はオープンソースソフトウェア(OSS)愛好者に適していると言えよう.この本では付録にて ACL と SBCL の両方のインストール方法をガイドしているが,全体としては初心者を対象に ACL に基づいて説明している.Emacs Lisp は Common Lisp ではないので,本書籍のほとんどの部分で役に立たないことを注意しておく.

この本の構成

この本は第1部と第2部に分かれており,この序章も含めて Common Lisp とそのプログラミングの説明を第1部に,Common Lisp を用いたAIプログラミングの部分を第2部に収めた.目的別に入手しやすいように,第1部と第2部を別々に入手可能にしたが,本来は全体として一体のものであり,第1部で第2部を引用したり,第2部から第1部を引用することがあることを,あらかじめお断りしておく.

通常のプログラム言語では,言語機能や装備されているデータ型の説明から始まるのが通例であるが,本書は最低限の関数定義の書き方と再帰プログラミングから説明を始め,Common Lisp の豊富な諸機能の説明は1部後半に回した.その理由は,Common Lisp の言語機能のあれこれを知るよりも,Lisp の本質を理解してもらうのが先決と考えるからである.Lisp の Lisp たる特徴を理解するのは大変であるが,それさえ掴まえてしまえば通常の言語機能などは言語仕様書などをたよりに自分で勉強することができる.Lisp プログラミングを身につけるには,最初は S 式と defun さえ分かればよいのである.

第1章は Lisp の導入であり,付録の記述に従って Common Lisp をインストールして立ち上げたところから始まる.この章ははじめて Lisp にさわる人たちを対象としているので,Emacs Lisp も含めて Lisp に触ったことのある人は飛ばしてもかまわない.Lisp の特徴である対話型の入出力と括弧の多いS式に慣れてもらうのが目的である.

第2章では関数定義の書式を学んで,Common Lisp に用意されているいくつかの述語と条件式の書き方を知り,ごく簡単なプログラミングに必要な最低限の知識を知ってもらう.実施例や問題の与え方は,順番に読んでいけば少しずつ無理なく進んでいけるように,配置してある.Common Lisp のプログラミング方法は知っているという方は飛ばしてもらってもかまわない.

第3章では丸々1章を費やして,再帰プログラムの書き方を学ぶ.再帰プログラミングこそが AIプログラミングに必須の技術であり,Lisp に特徴的なところであるにもかかわらず,最近の Lisp の教科書はこれについてほとんど記述していない.たとえば Peter Seibel の本はこれはこれで Common Lisp の教科書としては出色のものではあるが,なんと再帰についての記述がない.なぜ再帰かといえば,それが人工知能実現に必須の技術だからなのであるが,この章の問題を順にきちんと追っていけば,いままで再帰プログラミングで挫折した人も必ずクリアできるはずである.また,今では Lisp 処理系も Lisp でプログラムされているが,例題を見て,問題を解いていくことで,個々の Lisp 関数の Lisp における実装も類推がつくようになるはずである.Lisp を理解するためにも,再帰プログラミングは重要である.なお,この章における問題のほとんどは,The Little LISPer 第1版と Winston による LISP に記載のものである.

第4章は Lisp の変数束縛についてである.再帰プログラミングと並んで変数束縛も,もう一つの Lisp の本質である.昔の Lisp は現在なら動的変数と呼ばれるものであり,そのために非常にわざとらしくプログラムすると,Lisp をコンパイルしないで実行した場合とコンパイルして実行した結果が異なるコードを書くことができて,これをFUNARG問題という名前で呼んでいた.Common Lisp では他のプログラミング言語と同様に静的変数が基本となって,このFUNARG問題が一掃された.これは大きな進歩であったが,動的変数も特殊変数と宣言することで作ることができて,これが非常に有効に働く場合もあり,両者をきちんと使い分けることが Lisp プログラミングでは大事である.この章では,これらの変数の異なりを理解し,特殊変数,大域変数なるものを学んで,正しく使えるようにする.ここまでが,Common Lisp 初級プログラミングと言っていいかもしれない.

第5章では,それまで慎重に避けてきた副作用を伴う諸関数について学ぶ.第4章まではリストとはこういったものという紙面の字面上の理解でよかったが,ここでは cons セルとポインタのモデルを学んで,そのモデル上で作用する関数の使い方を学ぶ.Common Lisp は人工知能言語のアセンブラ言語とでもいうような特徴もあり,変数の参照透明性を確保した関数プログラミングもできれば,副作用ゴリゴリのプログラミングもできる.両方を学ぶことで,はじめて,バグのない効率的なコーディングができるようになる.

第6章は関数を引数に取る高階関数とMAP関数についてである.今日では多くの計算機言語がラムダ式を扱えるようになってきているが,Lispこそ ハスケル B. カリーと アロンゾ・チャーチによるラムダ計算に触発されて作られた関数型言語であり,プログラミングとCommon Lisp 実装の至る所で関数型言語の利点が発揮されている.また,ここでは改めて複雑な Common Lisp のラムダパラメータの書き方について学ぶ.この章によって自分でも高階関数を書くことができるようになる.

第7章はいよいよマクロである.Ruby, Python, C#など多くの言語が Lisp の先進的なプログラミング機能を取り入れて発展してきたが,いまもって Lisp のみに残されている機能が Lisp のマクロである.これは C などでいうマクロとは機能的に全く別物である.一部の人々からは嫌われている括弧の S 式であるが,データとプログラムの表現を区別しない S 式だからこそ Lisp のマクロは Lisp のみが実装できる機能なのである.マクロは Lisp を書けるようになった中級プログラマーが次にチャレンジしたいと思うものであり,第6章の高階関数とこの章のマクロを身につけて,立派な中級 Lisper と言える.

第8章はコンパイラについて学ぶ.と言ってもコンパイル結果として生まれるコードには立ち入らず,コンパイル時と実行時が分離されている Common Lisp の特徴を理解して,eval-when を使えるようになるのが目的である.

第9章ではじめて,Common Lisp の豊富なデータ型についてさらっと学ぶ.Common Lisp では自分で特有のデータ型も定義できる.deftype の使い方を説明するが,その部分は類書にはないものかも知れない.

第10章では,配列,文字列,シーケンスの詳細な使い方について触れる.

第11章では Common Lisp により,Scheme のREPL(Read-Eval-Print-Loop)を実装する.これにより,Lisp システムの実装の基本も理解されるであろう.また,静的変数の実装方法についても学ぶ.

第12章は CLOS の標準機能について学び,ANSI 標準ではないが主要な Common Lisp には備えられているメタオブジェクト・プロトコル(MOP)について簡単に学ぶ.CLOS についてのよい教科書が英語でも手に入らない現在では,この章が価値あると判断される人も大勢いるであろう.

第13章は Format 文について,第14章は Loop 文について説明するが,本書の自己充足的に記載するものであり,Peter Seibel を勉強した人には余分なところであろう.

第15章で最後にパッケージやモジュール機能の使い方を学ぶ.ASDF2についても簡単に触れるが,Quicklisp が普及してきているので,それに依存して使う分には ASDF を学ぶ必要性は薄れてきてはいる.この部分もなかなか類書に記載がないところである.

第16章からは第2部人工知能プログラミングに入る.第16章は人工知能プログラミング環境と称して,"Paradigms of Artificial Intelligence Programming"(PAIP) と "Artificial Intelligence: Modern Approach"(AIMA) の Lisp 環境を紹介し,次章以降で利用する各種ユーティリティ諸関数を説明する.

第17章は人工知能ではない人工無脳と言われるElizaプログラムである.Web上のボットやSiri のような対話機能を実装したいと思っている人には大いに参考になるであろう.

第18章は初期の人工知能システムである一般問題解決器(GPS)の紹介である.ここでは GPS の応用例として著者自身になる宇宙ロボットにおける計画実行システムを紹介する.

第19章は探索問題である.筆者自身も人工知能に取り組みだした当初思ったことであるが,AI=探索?と思われるほど,初期のAIプログラムの基本技術は要するに探索であった.ここでは深さ優先探索,幅優先探索,前向き探索,後ろ向き探索,A*アルゴリズムなど,探索の基本について学ぶ.

第20章でフレームシステムを紹介する.過去にフレームシステムとして多くのシステムが開発されてきたが,ここでは Charniak, Riesbeck, McDermott によるXRLを紹介する.

第21章はルールベースシステムである.ルールベースシステムも過去多くのシステムが開発されてきたが,ここでは確信度を導入した典型的なルールベースシステム MYCIN を紹介する.

第22章では Riesbeck と Schank による "Inside Case-based Reasoning" の記述に基づいて事例ベース推論について説明する.現在の Common Lisp で動く事例ベース推論システムはここで紹介するものだけであろう.

第23章では述語論理などこれ以降の章にて基本となる単一化(ユニフィケーション)について一章を起こして説明する.

第24章では一階述語論理について説明する.

第25章はプラニングである.PAIP にはプラニングの章はないし,AIMA では章立てて説明はあるが,掲載された疑似コードに相当する実コードはどこにもない.ここではプラニングに関する優れた教科書 Ghallab, Nau, Traverso の "Automated Planning Theory and Practice" の定式化に沿ったプログラミング例を紹介する.

第26章は Lisp で作る Prolog である.この章の内容はほぼ PAIP のそれと同じである.

最後に終章において,本書籍と人工知能プログラミングについて振り返って概観し,残されているもの,現在望まれている事項やレベルとの差異を明らかにして,将来への課題とそれに対する個人的な希望も述べることにする.