100言語Spedrdrun :エピソード86:Emacs Lisp
編集者戦争は終わった.TextMateスタイルエディタ(崇高なテキスト、原子、VSCode)を獲得した.Jupyter、Android Studio、およびそのような重要な使用のような言語固有のエディタ、そしてどうにか、メモ帳+はそのニッチを見つけました.特に「編集者戦争」の主な役者であるEmacsとVer . Emacsは、viスタイルの編集者(VimとNeovimが最近生きている)をどうにかするために、どうにか十分なvi diehardsがあります.Emacsのスタイルエディタには、以下のような種類がありません.
とにかく、私がここで興味を持っているのは編集者ではない.私はTextMateの初期の採用者であり、決して振り返っていなかった.
Emacs Lispはずっとパワフルで、Emacsの中から実行されたプログラムは全部書き込まれました.当時、それは奇妙に見えました、しかし、現在、あらゆるエディタはそのように働きます.Emacs Lispは基本的にLispの主要な方言でした、そして、私はそれがLipsのどれもひどく人気がないので、まだそうであると思います.Emacsが関連したとき、誰もそれが好きでありませんでした、そして、一般的なLisp、計画または他に何かに変わることについての一定の話がありました.今それはもはや重要ではない、生態系全体が死亡した.
一方vimscriptはEmacs Lispのようにどこにも大きくはありませんでした、そして、Vim World(Neovimによる)の残りのものはとにかくLuAに変わりました.
適切に
では、Emacs Lispをより良くするように拡張しましょう.追加します
ネーミングは本当にひどいです. なぜ私たちはこのような愚かさを行う必要がありますか
OK、いくつかの超基本的な機能プログラミングを試してみましょう.
Emacsを使用して皆が停止した後に、Emacs Lispは、「壊れないでください」モードを追加しました.
一歩一歩
少なくともUnicodeは働きます.エディタ固有の言語がUnicodeをサポートしていない場合は、当惑します.
よし、ちょっと複雑なことをしましょう.
Emacs Lispは「ファイルを読む」、「ランダムな要素」、「文字列を含む」といった多くの明白な機能を欠いている ファイルを読むには、“一時的なバッファ”を作成し、そのファイルにファイルの内容を挿入し、バッファの内容を読み込む必要があります readlineするには、それを行う必要があります 全体的にこのコードについての多くの小さなことはちょっと間違っている感じ
明らかにない.Emacsはエディタをアプリケーションプラットフォームにするパイオニアでした.Emacs Lispはその役割については十分でしたが、EmacsとEmacs Lispの両方は本当に時代遅れです.多分、Emacsはより良い言語、そしてより少ないGUI恐怖症で闘争チャンスを持っていたかもしれません、しかし、歴史はそれです.
言語自体に関しては、Emacs Lisp言語は奇妙なアーキチックなquirksでいっぱいです、そして、とても多くの基本的な特徴を逃します、そして、現代のLISSは少しよりよくそれをします.Arguably none of the Lisps is all that great , しかし、あなたがLISPにトライを与えたいならば、ラケットとクロジュールはずっと合理的です.
そして、いくつかのエディタプラグインをコード化したいならば、vscodeはすべてJavaScriptです、それで、あなたはそれを学ばなければなりません.
All code examples for the series will be in this repository .
Code for the Emacs Lisp episode is available here .
とにかく、私がここで興味を持っているのは編集者ではない.私はTextMateの初期の採用者であり、決して振り返っていなかった.
Emacs Lispはずっとパワフルで、Emacsの中から実行されたプログラムは全部書き込まれました.当時、それは奇妙に見えました、しかし、現在、あらゆるエディタはそのように働きます.Emacs Lispは基本的にLispの主要な方言でした、そして、私はそれがLipsのどれもひどく人気がないので、まだそうであると思います.Emacsが関連したとき、誰もそれが好きでありませんでした、そして、一般的なLisp、計画または他に何かに変わることについての一定の話がありました.今それはもはや重要ではない、生態系全体が死亡した.
一方vimscriptはEmacs Lispのようにどこにも大きくはありませんでした、そして、Vim World(Neovimによる)の残りのものはとにかくLuAに変わりました.
こんにちは、世界!
適切に
#!
Emacs Lispスクリプトを端末から実行できます.#!/usr/bin/env emacs -Q --script
(princ "Hello, World!\n")
$ ./hello.el
Hello, World!
それはコースのlispであるので、至る所で括弧.princ
人間に優しいprint
. 多くのEmacs Lisp関数はそのような不可解な名前を持ちます.フィズバズ
#!/usr/bin/env emacs -Q --script
; FizzBuzz in Emacs Lisp
(defun divisible (n m)
(= 0 (% n m)))
(defun fizzbuzz (n)
(cond
((divisible n 15) "FizzBuzz")
((divisible n 5) "Buzz")
((divisible n 3) "Fizz")
(t (number-to-string n))))
(dotimes (i 100)
(princ (fizzbuzz (+ i 1)))
(princ "\n"))
このコードはあまり悪くありませんが、すでにいくつかのマイナーな問題に遭遇します.(defun ...)
関数を定義する(dotimes (i n))
からの反復のみ0
to n-1
, ビルトインがないa
to b
反復処理(princ)
つの引数だけをとり、改行を出力しません.println
ちょうど働くだろう同等の機能princ
複数の引数を取る、それはそのような明白なことです、そしてほとんどの言語はそれだけで罰金をサポートして(cond ...)
のようですif/elsif
チェーンt
手段true
nil
手段false
, 空リストマクロ
では、Emacs Lispをより良くするように拡張しましょう.追加します
(dorange (i a b) ...)
多くの引数(prints ...)
.#!/usr/bin/env emacs -Q --script
(defun prints (&rest args)
(if (consp args)
(progn
(princ (car args))
(apply 'prints (cdr args)))))
(defun fib (n)
(if (<= n 2)
1
(+ (fib (- n 1)) (fib (- n 2)))))
(defmacro dorange (i a b &rest body)
`(let ((,i ,a))
(while (<= ,i ,b)
,@body
(setq ,i (+ ,i 1)))))
(dorange n 1 30
(prints "fib(" n ")=" (fib n) "\n"))
$ ./fib.el
fib(1)=1
fib(2)=1
fib(3)=2
fib(4)=3
fib(5)=5
fib(6)=8
fib(7)=13
fib(8)=21
fib(9)=34
fib(10)=55
fib(11)=89
fib(12)=144
fib(13)=233
fib(14)=377
fib(15)=610
fib(16)=987
fib(17)=1597
fib(18)=2584
fib(19)=4181
fib(20)=6765
fib(21)=10946
fib(22)=17711
fib(23)=28657
fib(24)=46368
fib(25)=75025
fib(26)=121393
fib(27)=196418
fib(28)=317811
fib(29)=514229
fib(30)=832040
一歩一歩progn
, car
, cdr
, setq
私はこれらが伝統的なLISPの名前であるということを知っています.consp
は「空のリスト」ですcar
リストの最初の要素を意味するcdr
リストの残りsetq
設定変数&rest
関数の残りの引数を意味する(apply 'prints (cdr args))
の代わりに(prints &rest (cdr args))
or (prints . (cdr args))
? 関数型プログラミング
OK、いくつかの超基本的な機能プログラミングを試してみましょう.
#!/usr/bin/env emacs -Q --script
(setq list '(1 2 3 4 5))
(setq add2 (lambda (n) (+ n 2)))
(print (mapcar add2 list))
(defun addn (n) (lambda (m) (+ n m)))
(setq add3 (addn 3))
(print (mapcar add3 list))
作成するadd2
を追加するラムダとして2
である.その後、我々は作成add3
それで3
. きっとそれは正しく働くでしょうか?$ ./functional.el
(3 4 5 6 7)
Symbol’s value as variable is void: n
井戸add2
働いたがadd3
でなかった、ワット?ここではEmacs Lispの主要な問題の一つに遭遇します.いくつかの非常識な理由emacslispすべてのダイナミックなスコープを使用します.これはかなりの機能的プログラミングを使用する任意のアイデアを殺す.オプションは壊れません
Emacsを使用して皆が停止した後に、Emacs Lispは、「壊れないでください」モードを追加しました.
#!/usr/bin/env emacs -Q --script
;; -*- lexical-binding: t -*-
(setq list '(1 2 3 4 5))
(setq add2 (lambda (n) (+ n 2)))
(print (mapcar add2 list))
(defun addn (n) (lambda (m) (+ n m)))
(setq add3 (addn 3))
(print (mapcar add3 list))
$ ./functional2.el
(3 4 5 6 7)
(4 5 6 7 8)
また、これらの余分な改行とは何です(print ...)
? prin1
and princ
改行を表示しないprint
印刷前と1つ後に、WTF?一歩一歩
(setq lest '(1 2 3 4 5))
- Emacs Lispが関数名をコールしようとせずにリストを関数呼び出しから区別するためにその引用符を必要とします1
(lambda (n) ...)
匿名関数n
(mapcar f list)
is map
, ひどいネーミングのもう一つのケースユニコード
少なくともUnicodeは働きます.エディタ固有の言語がUnicodeをサポートしていない場合は、当惑します.
#!/usr/bin/env emacs -Q --script
(defun prints (&rest args)
(if (consp args)
(progn
(princ (car args))
(princ "\n")
(apply 'prints (cdr args)))))
(prints
(length "Hello")
(length "Żółw")
(length "💰")
(downcase "Żółw")
(upcase "Żółw"))
$ ./unicode.el
5
4
1
żółw
ŻÓŁW
悪化する
よし、ちょっと複雑なことをしましょう.
#!/usr/bin/env emacs -Q --script
(defun read-file (path)
(with-temp-buffer
(insert-file-contents path)
(buffer-string)))
(defun read-lines (path)
(split-string (read-file path) "\n" t))
(defun random-element (list)
(nth (random (length list)) list))
(defun report-wordle-blocks (guess word)
(dotimes (i 5)
(let ((gi (substring guess i (+ i 1)))
(wi (substring word i (+ i 1))))
(princ
(cond
((equal gi wi) "🟩")
((string-match-p (regexp-quote gi) word) "🟨")
(t "🟥")))))
(princ "\n"))
(defun report-wordle (guess word)
(if (/= (length guess) 5)
(princ "Please enter a 5 letter word.\n")
(report-wordle-blocks guess word)))
(setq word-list (read-lines "wordle-answers-alphabetical.txt"))
(setq word (random-element word-list))
(setq guess "")
(while (not (equal guess word))
(setq guess (read-from-minibuffer "Guess: "))
(report-wordle guess word))
私の最初の試みは、驚くべきではない:$ ./wordle.el
Guess: raise
🟥🟩🟥🟥🟩
Guess: maybe
🟥🟩🟥🟥🟩
Guess: dance
🟥🟩🟥🟥🟩
Guess: vague
🟥🟩🟥🟨🟩
Guess: haute
🟩🟩🟩🟩🟩
一歩一歩split-string
そば"\n"
- その余分t
空の文字列を無視することを意味します(最後の改行後の最後のもののように)-全体のものは全く正しくないが、十分に閉じますrandom-element
リストからランダムな要素を返すreport-wordle-blocks
Wordleマッチ用の色付きブロックを出力する(string-match-p (regexp-quote gi) word)
文字列が別の機能を含んでいるかどうかをチェックする最も簡単な方法のようですEmacs Lispを使うべきですか?
明らかにない.Emacsはエディタをアプリケーションプラットフォームにするパイオニアでした.Emacs Lispはその役割については十分でしたが、EmacsとEmacs Lispの両方は本当に時代遅れです.多分、Emacsはより良い言語、そしてより少ないGUI恐怖症で闘争チャンスを持っていたかもしれません、しかし、歴史はそれです.
言語自体に関しては、Emacs Lisp言語は奇妙なアーキチックなquirksでいっぱいです、そして、とても多くの基本的な特徴を逃します、そして、現代のLISSは少しよりよくそれをします.Arguably none of the Lisps is all that great , しかし、あなたがLISPにトライを与えたいならば、ラケットとクロジュールはずっと合理的です.
そして、いくつかのエディタプラグインをコード化したいならば、vscodeはすべてJavaScriptです、それで、あなたはそれを学ばなければなりません.
コード
All code examples for the series will be in this repository .
Code for the Emacs Lisp episode is available here .
Reference
この問題について(100言語Spedrdrun :エピソード86:Emacs Lisp), 我々は、より多くの情報をここで見つけました https://dev.to/taw/100-languages-speedrun-episode-86-emacs-lisp-1hmlテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol