| Emacs Lisp | |
|---|---|
Emacsロゴ | |
| パラダイム | 関数型、メタ、リフレクティブ |
| ファミリー | Lisp |
| 設計者 | リチャード・ストールマン、ガイ・L・スティール・ジュニア |
| 開発者 | GNUプロジェクト |
| 初登場 | 1985年 (1985年) |
| 安定版リリース | 2024年6月22日(日) ( 2024-06-22 ) |
| タイピングの規律 | ダイナミック、強力 |
| スコープ | 動的、オプションで語彙的 |
| プラットフォーム | Emacs |
| OS | クロスプラットフォーム |
| ライセンス | GPLv3 |
| ファイル名拡張子 | .el、.elc、.eln |
| ウェブサイト | gnu.org/emacs |
| 影響を受けた | |
| Common Lisp、Maclisp | |
Emacs Lispは、 Emacs向けに作られたLisp方言です。Emacsに組み込まれている編集機能の大部分を実装するために使用され、残りの部分はLispインタプリタと同様にC言語で書かれています。
Emacs Lispコードは、Emacsの変更、拡張、カスタマイズに使用されます。コードを自分で書きたくない場合は、代わりに「カスタマイズ」機能を使用できます。この機能は、ユーザーがオプションを設定し、実行中のEmacsセッションでその効果をプレビューできる設定ページを提供します。ユーザーが変更を保存すると、「カスタマイズ」は必要なEmacs Lispコードをユーザーの設定ファイルに書き込みます。この設定ファイルは、「カスタマイズ」のみが使用する特別なファイルに設定できるため、ユーザー自身のファイルが変更される可能性を回避できます。
Emacs Lispはバイトコード[ 1 ] やネイティブコード[ 2 ]にコンパイルできるプログラミング言語であるだけでなく、 Emacsをバッチモードで呼び出すことで、UnixのBourneシェルやPerlのようにインタープリタ型スクリプト言語 としても機能します。この方法では、コマンドラインまたは実行可能ファイルから呼び出すことができ、バッファや移動コマンドなどの編集機能は、通常モードと同じようにプログラムで使用できます。Emacsをバッチモードで起動した場合、ユーザーインターフェイスは表示されません。渡されたスクリプトを実行して終了し、スクリプトからの出力が表示されます。
Emacs LispはElispとも呼ばれますが、同じ名前を持つ古い無関係なLisp方言も存在します。[ 3 ] [ 4 ]
他のLisp方言と比較して
Emacs Lisp はMaclispと最も関連が深いが、後にCommon Lispの影響も受けた。[ 5 ]命令型および関数型プログラミング手法をサポートしている。 Lisp はEINE や ZWEIなどの Emacs 派生プログラムのデフォルトの拡張言語であった。リチャード・ストールマンがGosling Emacs をGNU Emacs にフォークしたとき、関数をデータとして扱う機能など、その強力な機能から、彼は拡張言語として Lisp を選択した。 Common Lisp 標準はまだ策定されていなかったが、当時はSchemeが存在していたが、ワークステーション上での Schemeのパフォーマンスが比較的低い( Emacs の伝統的なホームであるミニコンピュータと比較して) ため、ストールマンはそれを使用せず、より簡単に最適化できると思われる方言を開発したいと考えていた。[ 6 ]
Emacsで使用されるLisp方言は、アプリケーションプログラミングで使用されるより現代的なCommon LispやScheme方言とは大きく異なります。Emacs Lispの顕著な特徴は、デフォルトでレキシカルスコープではなく動的スコープを使用することです。つまり、関数は呼び出し元のスコープ内ではローカル変数を参照できますが、関数が定義されたスコープ内では参照できません。最近、以下に概説する理由により、レキシカルスコープを使用するようにコードを更新する取り組みが継続されています。
| 1958 | 1960 | 1965 | 1970年 | 1975年 | 1980年 | 1985年 | 1990年 | 1995 | 2000 | 2005 | 2010 | 2015 | 2020 | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| LISP 1、1.5、LISP 2 (廃止) | |||||||||||||||
| Maclisp | |||||||||||||||
| InterLisp | |||||||||||||||
| MDL | |||||||||||||||
| Lispマシン Lisp | |||||||||||||||
| スキーム | R5RS | R6RS | R7RS スモール | ||||||||||||
| NIL | |||||||||||||||
| ZIL (ゾーク実装言語) | |||||||||||||||
| Franz Lisp | |||||||||||||||
| muLisp | |||||||||||||||
| Common Lisp | ANSI規格 | ||||||||||||||
| Le Lisp | |||||||||||||||
| MIT Scheme | |||||||||||||||
| XLISP | |||||||||||||||
| T | |||||||||||||||
| シェ・スキーム | |||||||||||||||
| Emacs Lisp | |||||||||||||||
| AutoLISP | |||||||||||||||
| PicoLisp | |||||||||||||||
| ガンビット | |||||||||||||||
| EuLisp | |||||||||||||||
| ISLISP | |||||||||||||||
| OpenLisp | |||||||||||||||
| PLTスキーム | ラケット | ||||||||||||||
| newLISP | |||||||||||||||
| GNU Guile | |||||||||||||||
| Visual LISP | |||||||||||||||
| Clojure | |||||||||||||||
| Arc | |||||||||||||||
| LFE | |||||||||||||||
| Hy | |||||||||||||||
例
Emacs Lispの開発は、汎用プログラミング言語の実装よりも、多用途のテキストエディタを作成するためのデータ構造と機能を提供するという目標に導かれました。例えば、Emacs Lispではファイルを1行ずつ簡単に読み込むことはできません。ファイル全体をEmacsバッファに読み込む必要があります。しかし、Emacs Lispは、モードによって定義された文、段落、またはより高い構文レベルでバッファテキストをナビゲートおよび変更するための多くの機能を提供します
以下は、Emacs Lispで書かれたEmacs拡張機能の簡単な例です。Emacsでは、編集領域をウィンドウと呼ばれる独立した領域に分割することができ、各領域には異なるバッファが表示されます。バッファとは、Emacsのメモリに(ファイルから読み込まれる場合もある)読み込まれたテキスト領域で、テキストドキュメントに保存することができます。
ユーザーはデフォルトのC-x 2キーバインドを押すことで新しいウィンドウを開くことができます。これはEmacs Lisp関数 を実行しますsplit-window-below。通常、新しいウィンドウが表示されると、以前のものと同じバッファが表示されます。次に利用可能なバッファを表示したいとします。これを行うには、ユーザーは既存のEmacs Lispソースファイルまたは空のEmacsバッファに、以下のEmacs Lispコードを記述します。
( defun my-split-window-func () (インタラクティブ) ( split-window-below ) ( set-window-buffer ( next-window ) ( other-buffer )))( global-set-key ( kbd "Cx 2" ) #' my-split-window-func )最初の文 は(defun ...)新しい関数 を定義します。この関数は(古いウィンドウ分割関数)my-split-window-funcを呼び出し、新しいウィンドウに別の(新しい)バッファを表示するように指示します。2番目の文 は、キーシーケンス「Cx 2」を新しい関数に再割り当てします。 split-window-below(global-set-key ...)
これはadviceという機能を使って記述することもできます。この機能を使うと、ユーザーは独自の関数を定義する代わりに、既存の関数のラッパーを作成することができます。これにはキーバインドを変更する必要がなく、元の関数が呼び出された場所であればどこでも動作し、記述が簡単になるという利点がありますが、デバッグが複雑になるという欠点もあります。このため、 GNU Emacsのソースコードではadvice は許可されていません[ 7 ]。しかし、ユーザーが望むなら、 advice 機能をコード内で使用して上記のコードを以下のように再実装することができます。
( defadvice split-window-below ( my-window-splitting-adviceの後に最初に()をアクティブにする) ( set-window-buffer ( next-window ) ( other-buffer )))これはsplit-window-below、関数の残りの部分を実行した後に、ユーザーが指定したコードが呼び出されるたびにそのコードを実行するように指示します。アドバイスは、元の関数の前、関数の周囲(文字通り元の関数をラップする)で実行するように指定することも、アドバイスの結果に基づいて条件付きで元の関数を実行するように指定することもできます。
Emacs 24.4では[ 8 ]このdefadvice仕組みをadvice-add、より柔軟でシンプルであるとされるに置き換えました。[ 9 ]上記のアドバイスは、新しいシステムを使用して次のように再実装できます。
( defun switch-to-next-window-in-split ( ) ( set-window-buffer ( next-window ) ( other-buffer ) ))( advice-add 'split-window- before #' switch-to-next-window-in-split )これらの変更は、コードが評価されるとすぐに有効になります。再コンパイル、Emacsの再起動、あるいは設定ファイルの再ハッシュは必要ありません。コードをEmacsのinitファイルに保存した場合、Emacsは次回起動時に拡張機能を読み込みます。そうでない場合は、Emacsの再起動時に変更を手動で再評価する必要があります。
ソースコード
Emacs Lispのソースコードは、ファイル名の接尾辞が「 」であるプレーンテキストファイルとしてファイルシステムに保存されます。ユーザーのinitファイルは例外で、Emacs Lispコードとして評価されるにもかかわらず、「 」として表示されることがよくあります。1990年代半ば以降、Emacsは と もロードします。さらに、ユーザーはコマンドラインで任意のファイルを設定ファイルとしてロードするように指定したり、設定ファイルをロードしないことを明示的に指定したりできます。ファイルがロードされると、 Emacsプログラムのインタープリタコンポーネントが関数と変数を読み取り、解析し、メモリに保存します。その後、それらは他の編集機能やユーザーコマンドで使用できるようになります。関数と変数は、エディターを再起動したり設定ファイルを再ロードしたりすることなく、自由に変更および再定義できます .el.emacs~/.emacs.el~/.emacs.d/init.el
時間とメモリを節約するため、Emacsの機能の多くは必要なときだけ読み込まれます。Emacsに同梱されているオプション機能の各セットは、パッケージまたはライブラリと呼ばれるEmacsコードの集合によって実装されています。例えば、プログラムのソースコード内のキーワードをハイライトするためのライブラリや、テトリスゲームをプレイするためのライブラリなどがあります。各ライブラリは、1つ以上のEmacs Lispソースファイルを使用して実装されています。ライブラリは、その機能を起動および制御するための 1つ以上のメジャーモードを定義できます。
Emacs 開発者は特定の関数を C で記述します。これらはプリミティブであり、組み込み関数またはサブルーチンとも呼ばれます。プリミティブは Lisp コードから呼び出すことができますが、C ソースファイルを編集して再コンパイルすることによってのみ変更できます。GNU Emacsでは、プリミティブは外部ライブラリとして使用できません。プリミティブは Emacs 実行可能ファイルの一部です。XEmacs では、オペレーティング システムの動的リンクサポートを使用して、このようなプリミティブを実行時にロードできます。関数がプリミティブとして記述されるのは、Emacs Lisp からは利用できない外部データやライブラリにアクセスする必要がある場合や、C と Emacs Lisp の速度の比較によって意味のある違いが生じるほど頻繁に呼び出される場合です。
ただし、C コードのエラーはセグメンテーション違反や、エディターをクラッシュさせるようなより微妙なバグにつながりやすいため、また、Emacs Lispガベージ コレクターと正しく対話する C コードを記述するとエラーが発生しやすいため、プリミティブとして実装される関数の数は必要な最小限に抑えられます。
バイトコード
バイトコンパイルにより、Emacs Lispコードの実行速度が向上します。Emacsには、 Emacs Lispソースファイルをバイトコードと呼ばれる特別な表現に変換できるコンパイラが含まれています。Emacs Lispバイトコードファイルのファイル名には「 」という接尾辞が付きます。ソースファイルと比較して、バイトコードファイルは読み込みと実行が速く、ディスク容量の占有量が少なく、読み込み時のメモリ使用量も少なくなります .elc
バイトコードはプリミティブコードよりも実行速度が遅いですが、バイトコードとしてロードされた関数は簡単に変更・再ロードでき、バイトコードファイルはクロスプラットフォームソフトウェアです。Emacsに同梱されている標準のEmacs Lispコードはバイトコードとしてロードされますが、対応するソースファイルも通常はユーザーの参照用に提供されます。ユーザーが提供する拡張機能は、サイズも計算量もそれほど大きくないため、通常はバイトコンパイルされません。
言語機能
「cl-lib」パッケージは、 Common Lispのかなり大きなサブセットを実装しています。このパッケージは、既存のEmacs Lisp関数定義をCommon Lispに似たものに上書きする以前の「cl」パッケージを置き換えます。一方、「cl-lib」パッケージはEmacs Lispのスタイルガイドラインに厳密に従い、定義する各関数とマクロに「cl-」(例えば、cl-defun組み込み関数の名前と競合しないdefun)を接頭辞として付けることで、「cl」パッケージがロードされるたびに発生する可能性のある予期しない動作の変化を回避します
Emacs Lispは(他のLisp実装とは異なり)末尾呼び出し最適化を行いません。[ 10 ]末尾再帰の最適化を行わないと、最終的にスタックオーバーフローが発生する可能性があります。
apelライブラリは、 polysylabi プラットフォーム ブリッジを利用して、移植可能な Emacs Lisp コードの作成を支援します。
Emacs LispはCommon LispのようなLisp-2であり、他の変数に使用される名前空間とは別の関数名前空間を持っていることを意味します。[ 11 ]
動的スコープから語彙スコープへ
MacLispと同様に、Emacs Lispは動的スコープを使用し、バージョン24以降では静的(またはレキシカル)スコープをオプションとして提供しています。 [ 12 ]これは、ファイルローカル変数を設定することで有効にできますlexical-binding。[ 13 ] [ 14 ]lexical-letこのオプションが追加される前は、 (現在は非推奨の)「cl」パッケージのマクロを使用して、効果的なレキシカルスコープを提供できました。 [ 15 ]
動的スコープでは、プログラマが関数のスコープ内で変数を宣言すると、その関数内から呼び出されるサブルーチンでその変数が利用可能になります。当初、これは最適化を目的としていました。当時、レキシカルスコープはまだ一般的ではなく、パフォーマンスも不確実でした。コンピュータ科学者のオリン・シヴァーズの回想によれば、「RMSがemacs lispを実装していたとき、なぜ動的スコープなのかと尋ねたところ、彼の正確な答えは、レキシカルスコープはあまりにも非効率すぎるというものでした。」[ 16 ]動的スコープは、ユーザーによるカスタマイズの柔軟性を高めることも意図されていました。しかし、動的スコープにはいくつかの欠点があります。第一に、異なる関数内の変数間の意図しない相互作用により、大規模なプログラムでは簡単にバグが発生する可能性があります。第二に、動的スコープでの変数へのアクセスは、レキシカルスコープよりも一般的に遅くなります。[ 17 ]
参照
参考文献
- ^ 「Emacs Lispのバイトコンパイル」。GNU Emacsマニュアル。2024年6月14日閲覧
- ^ 「Emacs Lispのネイティブコードへのコンパイル」 . GNU Emacsマニュアル. 2024年6月14日閲覧。
- ^ HEDRICK at RUTGERS (Mngr DEC-20's/Dir LCSR Comp Facility (1981-12-18)) 。「Common Lispの実装に関する情報」" . SU-AIのrpg、MIT-AIのjonlへの手紙。2016年9月20日にオリジナルからアーカイブ。 2019年7月28日に取得。Elisp
(Rutgers/UCI Lispの拡張実装)が実質的に完成したため、Lisp実装の経験が多少あります。
{{cite press release}}: CS1 maint: 数値名: 著者リスト (リンク) - ^「CCA EMACSの広告」。Unix Review、1984年12月、p. 16。CCA
EMACSおよびElispはCCA Uniworks, Inc.の商標です。
- ^「GNU Emacs LispはMaclispから大きく影響を受けており、Common Lispからも少し影響を受けています。Common Lispをご存知であれば、多くの類似点に気付くでしょう。しかしながら、GNU Emacsのメモリ使用量を削減するために、Common Lispの多くの機能が省略または簡略化されています。簡略化があまりにも劇的であるため、Common Lispのユーザーは非常に混乱するかもしれません。GNU Emacs LispとCommon Lispの違いについては、随時解説していきます。」 - Emacs Lispマニュアル「はじめに」の「歴史」セクションより(Emacs 21時点)
- ^「GNUオペレーティングシステムの開発こそが、私がGNU Emacsを書くきっかけとなったのです。その過程で、私はLispの実装を可能な限り最小限にすることを目指しました。プログラムのサイズは非常に大きな懸念事項でした。1985年当時、仮想メモリのない1MBマシンを持っている人たちがいました。彼らはGNU Emacsを使いたいと考えていました。そのため、プログラムを可能な限り小さくする必要がありました。」 -「私のLisp体験とGNU Emacsの開発」より
- ^ "Re: [Emacs-diffs] /srv/bzr/emacs/trunk r111086: gmm-utils.el (gmm-flet") . Lists.gnu.org. 2012年12月5日. 2013年8月18日閲覧。
- ^ 「NEWS.24.4」 .
- ^ 「古いアドバイスの移植」。
- ^ 「付録C Common Lispの移植」 Gnu.org 2019年10月28日閲覧。Lispプログラマー
は、現在のEmacs Lispコンパイラが末尾再帰を最適化していないことに注意する必要がある。
- ^ 「Google グループ」 . groups.google.com .
- ^ 「Emacs 24.1 リリース」 . Lists.gnu.org . 2013年8月18日閲覧。
- ^ 「字句バインディング」 . Lists.gnu.org. 2011年4月1日. 2013年8月18日閲覧。
- ^ 「動的バインディングとレキシカルバインディング」 . EmacsWiki. 2013年5月17日. 2013年8月18日閲覧。
- ^ 「Obsolete Lexical Binding」 . GNU Emacs Common Lisp Emulation . GNU Press . 2021年5月27日閲覧。
- ^ "T" . People.csail.mit.edu . 2013年8月18日閲覧。
- ^サム、フェザーストン;ウィンクラー、スザンヌ (2009-06-02)。プロセス。ウォルター・デ・グルイテル。ISBN 978-3-11-021614-1。
外部リンク
- GNUプロジェクトの公式サイト
- Emacs Lispリファレンスマニュアル、GNUプロジェクト
- Emacs Lispプログラミング入門、GNUプロジェクト
- Emacs Lisp Elements、Protesilaos Stavrou のウェブサイトより