Lispによるプログラミングに関する世界観です。
Lispでは、S式と呼ばれる、カッコを多用したコードの記法を行います。
S式においては、カッコの中の第一要素が関数名(あるいはマクロ名)となり、その後のパラメータはすべて関数の引数となります。
つまり、
(関数名 引数1 引数2)
となります。カッコはネストして入れ子にすることもできます。
Lispにはさまざまな方言があり、S式で記述するスタイルは変わりませんが、用意されている関数などが異なります。
Lispの方言のひとつであるCommon Lispでは、自分独自の関数はdefunで宣言します。
(defun add100 (x) (+ x 100))
この関数add100は、数値に100を足し算します(+という別の関数を使っている)。
これを
> (add100 200) 300
のように呼び出すことができます。
2024.08.13
S式によるカッコを多用したプログラミングでおなじみの、Lispについて。
人工知能の研究で使われることが多い。(最近は、人工知能はPythonのライブラリが豊富でもある。)
Emacs Lispと言う、テキストエディタEmacsの拡張言語として採用されていることで有名で、EmacsはLispによってコマンドシェルからメールクライアントまで、何でも出来る万能アプリケーションになる。
コンパイラが作りやすいことで有名で、たくさんの方言がある。主に使われているのは、Common LispとSchemeである。
あまり使われていないが、GNU公式のマクロ拡張言語として、Guileがある。
Lispでは、プログラム自身がS式と呼ばれる「括弧をたくさん使うリスト型のデータ」にすることができます。
これは、Lispの持つ、「プログラム自身をデータにできる」という強力な特徴です。
たとえば、Emacs Lispでは、Emacsというテキストエディタの中で、Lispをマクロとして実行できます。このため、Lispを使って「Emacsを拡張する」ことができます。
また、プログラムをデータとして扱うことで、人工知能・AIの開発にも、大きくLispは貢献しています。
こうしたプログラムをデータとして扱うのは、数学的です。たとえば、足し算が1+2=3である時、1と2と3はデータであり、必要なのは+という「基本となる関数」だけである、ということが言えます。Lisp的には、
(+ 1 2)
という簡単なS式でこのプログラムを表現できると同時に、この(+ 1 2)それ自体がひとつのS式によるデータであり、このデータを他の関数に送ったりするなどが可能です。プログラム=データ、という発想がLispの根底にあると言えるでしょう。
また、Lispの神髄は、ただプログラムをデータとして扱えるだけではなく、「データを作成するように、プログラムを作成できる」ということです。プログラムからプログラムを作成することが簡単にできる、これが、Lispの人工知能・AIとの親和性が高い理由です。
2024.08.13編集
Lispは、基本的に全てのプログラムを関数とマクロによって行う。関数型言語の先駆である。
後日注記:Lispは再帰と関わり合いが深い。関数とマクロによってプログラムを記述する際、分岐やループをどのように表現するかは大きな問題となるが、Lispでループを行うためには、自らの関数を関数内部で呼び出す再帰的ループを使う。
S式は、括弧を多用するLispのプログラムコードのスタイル。
後日注記:S式では、プログラムについてもリストデータについても同じ括弧を使って記述するため、プログラムをリストとして扱ったり、リストをプログラムとして扱ったりすることができる。
LispはFORTRANに次いで二番目に古いプログラミング言語として知られる。
後日注記:要するに、FORTRANが生まれた次にLispが生まれた。Lispはプログラミング言語の最初期からある言語でありながら、今でも使われている。
Common Lisp入門を参照のこと。
Schemeを参照のこと。
evalを使うことで、文字列をLispの式として評価できる。Lispはコンパイル言語として作られたが、evalによってインタープリタ言語として使うこともできる。
リフレクションとevalも参照のこと。
2023.03.08編集
Lispは処理系を作るのが簡単であると言われる。基本的な字句解析と構文解析、そして変数とevalぐらいしか必要でない。
ただ僕はLispインタプリタを作ったことがないので、詳しいことは以下を参考にしてほしい。
2023.03.08編集
Lispのカッコとインデントについて。
基本的に、カッコだけを詳しく読むのではなく、インデントに着目してコードを読むことが必要。
同じ関数の引数などは、頭を揃えてインデントする(揃えインデント)。関数名に続く引数などは、一定のスペース(空白2つなど)で字下げを行う(深さインデント)。どちらを使うかは場合による。
2023.11.04
ANSI Common Lisp (スタンダードテキスト)を参考に執筆しました。
自分の書いたブログ「わたしの名はフレイ」2020/09/15より。
また、「プログラミング言語の通りにプログラムを書くだけではなく、プログラミング言語そのものを作ることや、プログラムを書くためのプログラムを書く」といったことが、Lisp界隈では昔から行われている。
これはLispの大きな特徴である「S式」、すなわちデータもプログラムも同じ「リスト」の形式で書かれるという特徴だが、関数とマクロによって「Lisp言語そのものをLispで拡張できる」というLispでは「プログラミング言語そのものを自分の書きたいプログラムに合わせて作っていく」という方式がとられる。
このように書かれたプログラムは「ボトムアップ的アプローチ」などとも呼ばれ、TeXなどは最初期のこうしたプログラムであると言われる。
Lispは抽象度が高く、RubyやPythonに備わっている機能を昔から備えているほか、実行速度も他の高級言語に負けず劣らず速いため、「コードが短くやりたいけどRubyやPythonは遅くて複雑」という人には、Lispはとてもおすすめである。
Lispでは、「プログラミング言語のすべてを関数とマクロで表現する」ということをした結果、「プログラムコードとリストデータが同じ記述で表現できる」という特徴と、「プログラミング言語自体を拡張して自分の好きなプログラミング言語に変更できる」という特徴をあわせもつようになった。
関数を表現するのもリストデータを表現するのも括弧を使ったS式で表現するため、「プログラムコードをデータとして扱う」、すなわち「プログラム自体をプログラムで扱う」ということが容易にできる。
また、言語的なキーワードからopen-close文などのほとんどを関数やマクロなどで行う結果、「自ら関数やマクロを追加することで、プログラミング言語の仕様そのものを柔軟に変えられる」ということも容易にできる。LispプログラマはLispをそのままで使うのではなく、自らカスタマイズしてLispの上に自分のLispを構築し、その上でプログラムを記述する。
また、関数ポインタを使ったC言語に比べて、はるかにスマートに関数オブジェクトを変数として表現できる(たとえば無名関数を返す関数は簡単に書ける)のは、JavaScriptやRubyなどでも見られる特徴だが、古くからLispプログラマがやっていたことでもある。
このような特徴のあるLispは、なんと「LispプログラムによってLispコードを書く」、すなわちプログラムを書くことのできるプログラムを書くことができます。
Lispにおいては、プログラマがプログラムを人力で書くだけではなく、プログラマによって記述されたプログラムによってプログラムを自動的に生成することができるのです。
まさに、Lispは「人類を超えたプログラミング言語」であると言えます。
このような特徴があるLispは、人工知能の研究に昔からよく使われていました。最近では科学計算・データ解析・機械学習ライブラリの豊富なPythonに人工知能界での主力言語の座を奪われつつあります。
Lispで拡張できる最強のテキストエディタEmacs(全能のテキストエディタviと最強の座を競っている)の作者であり、GNU Projectの創始者、GPLの考案者であることでも知られるリチャード・M・ストールマンは、MITのAIラボに居たことでも有名です。最近はストールマンも失言メールでFSFから追い出されるなどオープンソース界は大荒れです。
Lispは拡張性豊かな言語である。まるで「プログラミング言語を作る」かのように、関数やマクロでLisp自体を拡張していける。
ボトムアップアプローチで、まず「Lisp言語を作り」、その上で「作った言語でプログラムを書く」といったことが可能になる。
また、Lispは関数型言語であり、「関数を返す関数」のようなものが簡単に書ける。
Lispは素早いインプリメントを可能とし、プランの際に絶対的な正しい仕様を書けなくても、プラン自体を小さくし、少ない時間でインプリメントを行うことができる。
このような特徴のため、C++を学ぶことでBASICが使いづらいものになるように、Lispを学ぶことでC++が使いづらいものになる。
(ANSI Common Lisp (スタンダードテキスト)を参考に執筆しました。)
lambdaとクロージャを組み合わせると、関数を返す関数を作ったとして、その関数から外部のスコープにある変数を参照できる。このようなことができるということがLispのほかの言語に対する大きな優位性である。
これが意味するところは、たとえば無名関数をlambdaで返す関数があったとして、それらの関数からその関数の定義されたスコープにある変数を参照できる、すなわち、すべての無名関数から同じデータにアクセスできるということを意味する。
ANSI Common Lisp (スタンダードテキスト)では、Lispについて「オブジェクト指向を超える」と表現している。僕はまだこの本を読んでいる途中であるため、著者の真意は分からない(まったく違うことを言っているかもしれない)。だが、僕が思うに、このようなLispの特徴はまさにオブジェクト指向を超えていると思う。
Lispは「神の言語」という異名をもっていて、その理由を以下のページが解説されています。とても面白い内容で、ドメイン特化言語(専門の知識に特化した言語)と汎用言語の違いなど、多くの勉強になる点があるので、プログラミング言語について学ぼうとする人に読まれることをおすすめします。
「ANSI Common Lisp (スタンダードテキスト)」と「On Lisp」を参考に執筆しました。
Lispの本質が何かと言えば、「プログラムコードとデータを同じものとして扱う」ということだと思います。
関数型言語としては、Lisp以外にHaskellがありますが、Haskellでは「関数と変数を同じものとして扱う」という発想をします。
Lispでは、これに加えて、「プログラムコードとデータを同じものとして扱う」という発想をします。
たとえば、クロージャを返したり関数を引数に渡して関数を実行したりという点では、「プログラムコードをデータのように渡す」ということができます。
あるいは、マクロやS式のリストを使うことで、「プログラムコードをプログラムコードからデータのように自動作成する」ということができます。
あるいは、evalなどを使うことで、「データをプログラムコードのように実行し、式を評価する」ということができます。
このようなLispの考え方は、UNIXとよく似ています。特に、OSとユーザーランドソフトウェア、あるいはソースコードとバイナリなどの点で、UNIXは「テキストファイルとしてプログラムを解析する」ということを行います。
2023.09.04
もうひとつ、Lispの優れた点があるとしたら、階層的なレイヤーを作ることができるという点です。
Lispでは、あらかじめ言語で提供されている関数やマクロと同じものを、自分で作って使うことができます。その独自に作った関数やマクロは、あらかじめ用意されている関数やマクロと、何も変わりません。
なので、Lispの上に自分の言語を作り、その上でプログラムを開発できます。
これはたとえば、Ruby on Railsなどと似ています。C言語のRubyインタープリタの上に、Rubyコードの水準があり、その上にさらにMVCフレームワークのRailsの水準があり、その上にWebアプリケーションを作ります。このようなことは、Railsが登場する何年も前から、Lispが、Webだけではなく多くの領域で行ってきたことなのです。
2023.09.04
Lispのほかの優れた点は、C言語ではできない関数型のプログラミングができることです。C言語は、プログラマに命令型で逐次的な手続き的なプログラミングを強いますが、これによってプログラマの思考能力が、C言語的な命令型プログラミングしか考えられなくなってしまい、「退化」してしまうのです。
Lispを使うことで、C言語では推奨されていない、あるいはそもそもできないような、高水準の抽象的なプログラミングができます。Lispハッカーはいつもそのように、C言語ではできないような高水準の思考をしています。そのように、Lispを使うことで、C言語で退化した知性を、Lispが再び取り戻してくれるのです。
(2023-09-04の日記に関連する内容があります。)
2023.09.04
2023.12.17編集
Lispは人工知能の研究によく使われる。AIも参照のこと。
特に多いのが、テキストエディタEmacsの拡張・マクロ言語としての利用である。
標準的なLisp言語。たくさんのLisp方言のスーパーセットとして作られたため、言語仕様が巨大。
Common Lisp入門も参照のこと。
Lispの方言の1つ。真にLispに必要な機能は何かを追究して作られている。
Schemeも参照のこと。
ご存じGNU Emacs。viと並んで最強のテキストエディタとして有名。
Emacs Lispと呼ばれるマクロ言語と内蔵の処理系によって自由に拡張することができる。そのため、テキストエディタというよりも環境に近い。テキストエディタなのに、メーラーになったりする。
Emacsも参照のこと。
Lispで拡張できるX11のウィンドウマネージャ。
Lispによるパッケージマネージャ。
Windowsにおける「Emacsライク」なエディタ。Common Lispによって拡張することができる。
xyzzyを参照のこと。
僕の大好きだったLispプログラマPaul GrahamのLisp入門書「On Lisp」の日本語訳がネットで無料で公開されています。
HTML版は少しおかしなところがあるので、PDF版を印刷して見た方が良いかもしれないです。
加えて、同じ著者によるCommon Lispの入門書「ANSI Common Lisp」が以下にあります。上級者向けの「On Lisp」と対になっています。
後日注記:ポール・グレアムによる「ANSI Common Lisp」と「On Lisp」はLispの定番の書籍であり、「ANSI Common Lisp」でCommon Lispの基本となる文法が分かり、「On Lisp」ではその先にある「そのプログラムをなぜそのように書くのか」という理由や根拠が説明されています。この二つの書籍を読めば、Lispはマスターできます。欠点があるとしたら、コードや説明がCommon Lispで書かれていること。SchemeではなくCommon Lispで書かれているために、Common Lispを学ばなければいけません。
後日注記:ポール・グレアムの「On Lisp」は、多くの章がマクロに割かれています。もちろんそれ以外の内容もありますが、「On Lisp」で言わんとしていることは、「いかにLispのマクロを書くか」ということです。「On Lisp」を読むことで、Common Lispでどのようにマクロを使ったプログラミングを行うか、ということが分かります。
2023.09.04編集
2023.09.08編集
Paul Grahamはさまざまなエッセイを書いていることでとても有名です。
以下は有名で面白い記事。
Eric S. Raymondによる「ハッカーになろう」など。Lispについての言及がある。
関数型プログラミングも参照のこと。
ユーティリティ開発も参照のこと。
書籍
個人的に好きなLispプログラマのポール・グレアムのベンチャー起業論など。