Emacs Lispで感じた書き散らすプログラミング体験

この記事は、はてなエンジニア Advent Calendar 2023の2024年1月16日の記事です。

昨日は id:fxwx23 さんによる「Simulator.app の「Stay On Top」をキーボードショートカットで切り替える」でした。 かゆい所に手が届かないこと、よくありますよね。その際にシュッとスクリプトを書いたりして不便を解消する姿は見習いたいと思います。

始めに

自分は普段テキストエディタEmacs を使っています。 EmacsEmacs Lisp というプログラミング言語でエディタの設定を記述できますが、今まで設定を記述する以外の目的で Emacs Lisp を書いたことがなく、プログラムっぽいプログラムを書いたことはありませんでした。

ふとこのことが気になって、年末年始の休みに簡単なプログラムを作ってみました。

実際に書いてみると、他の言語ではあまり体験したことのないようなプログラミング体験が出来ました。 ここでは Emacs Lispプログラミング言語として書いたときに得たプログラミング体験と、その感想について書いています。

Emacs Lisp でのプログラミング体験

LTSV 文字列をリストに変換する関数の実装を進めることを例として見ていきます。 以下は実装の一例です。Lisp について知らなくても、雰囲気でも何をやっているかがわかると思います。

(defun parse-ltsv-string (ltsv-string)
  "引数の LTSV の文字列を リストのリストにする ((key1 value1) (key2 value2))."
  (let ((values '()))
    (dolist (pair (split-string ltsv-string "\t"))
      (let ((key-value (split-string pair ":")))
        (push key-value values)))
    values))

(parse-ltsv-string "key:value\tname:miki_bene")
;; => (("name" "miki_bene") ("key" "value"))

この関数の実装過程で 4行目の (split-string ltsv-string "\t") の返り値が実際にどんな値が返るのか、確認してみたかったとします。 他の言語なら REPL を起動したり、ブラウザ上で実行できる Playground で試したりするところですが、Emacseval-last-sexp *1というコマンドを使うことで Emacs 上で実行が出来ます。

(defun parse-ltsv-string (ltsv-string)
 ...
)

;; 以下のコードの括弧の末尾にカーソルを配置し、
;; C-x C-e キーバインドで eval-last-sexp コマンドを実行する
(split-string "key:value\tname:miki_bene")
;; => ミニバッファに ("key:value" "name:miki_bene") が表示される

このように、編集しているプログラムから全く離れずに書いたコードを実行できます。

また、eval-last-sexp はどこでも実行できるので、例えば関数の中で全然違う処理をいきなり書いて実行することも出来ます。

(defun parse-ltsv-string (ltsv-string)
  ...

  ;; dolist でループ処理を行う際の動きを見たいので
  ;; *Messages* バッファに文字列を出力する
  (dolist (pair (split-string "key:value\tname:miki_bene" "\t"))
    (message "%s" pair)) ;; ここで C-x C-e コマンドを実行する
  ;; => *Messages* バッファに
  ;; key:value
  ;; name:miki_bene
  ;; nil
  ;; が出力される
  
  ;; 以下は書いている途中の処理
  (let ((values '()))
  ...
)

実は最初のコードもコマンドラインで実行した結果ではなく、Emacs 上で評価した結果を貼りつけているだけでした。

感想

例のように、Emacs Lisp では今書いているプログラムからほとんど離れずに処理を試したり、関数を実行できます。

実際に Emacs Lisp を書いていた際は、関数定義中の処理の中に具体的な値を入れて試す→動くことを確認したら値を変数に置き換えて続きを書き進める→また確認したくなったら具体的な値を入れて試す……を繰り返しながら実装を進めていました。 この繰り返しをすると気づいたらプログラムが出来上がっており、書いたプログラムが動くことの確信がほぼ持てているといった状態になっていました。

他のプログラミング言語で実装を進める際も似たようなことは行っているはずですが、Emacs Lisp の場合は処理の記述と実行の間がとてもシームレスで、絶え間無くプログラムを書き進められる感覚がありました。

もちろん Lisp 自体でつまずくことはあったので、言うほど絶え間無くではありませんでした。 ただ、書いてすぐに実行してフィードバックが返る素朴な楽しさがありました。

関数の中で全然違う処理を書いて実行できるのは滅茶苦茶だなと思いつつも、好きな場所に好きに書いても実行できる感覚は真っ白な自由帳に落書きを書いているみたいで、それも楽しくありました。

他のエディタで類似の機能はないのか

Emacs Lisp 以外で同様のものはないかと探してみると、VSCode の拡張に似た機能がありました。 選択した範囲を REPL に流し込み実行できるといったもので、割と感覚は近いかもしれません。

ただし Emacs Lisp の場合は評価した結果が残るので、以前評価されていれば選択していない部分の関数定義やライブラリ読み込みも使えるのは大きな違いかもしれません。 評価が残ってしまうのは意図しない結果になる時もありますが、その場で実行する場面においては基本利便性の方が高いだろうと感じています。

まとめ

Emacs Lisp を書いて、他の言語ではあまり体験できない実装体験が出来ました。 普段の業務では Perl や Go, TypeScript を書いています。これらの言語が悪いわけではない(むしろ静的型付けの方が好ましい)ですが、普段はあまり感じない書き散らす楽しさを久しぶりに感じました。

たまにはこういった自由帳のような言語で遊んでみるのもよいかもしれません。

はてなエンジニア Advent Calendar 2023、明日は id:hagihala さんです!