🥞

Parinferのすすめ

2022/12/09に公開

この記事は Clojure Advent Calendar 2022 の12月09日分に向けた記事です。

TL;DR

  • Clojure Advent Calendar だけと Clojure 色は薄いです
  • Paredit もいいけど Parinfer もいいよ
  • Structural Editing 使えば Lisp の括弧は怖くないよ

Structural Editing

Lisp と言えば大量の括弧からその見た目だけで敬遠されることで有名(?)ですが、
同時に Lisper には閉じ括弧が見えない/閉じ括弧は意識する必要がないという意見がでることでも有名(?)です。

その秘密は PareditParinfer などを使った Structural Editing です。

Structural Editing では括弧の対応は自動的に(強制的に)保たれるため、括弧の数などを意識する必要はなくなり Lisp のコードを安全に素早く書くことが可能となります。
そのため Lisper にとって Structural Editing は無くてはならない存在といっても過言ではありません。

Paredit

Structural Editing で一番使われているのは恐らく Paredit かと思います。
Paredit では主にショートカットを使って Slurp (e.g. カーソル配下のフォームに前後の要素を吸い込む)、Barf (e.g. カーソル配下のフォームから先頭/末尾の要素を吐き出す) といった操作を行いつつコードを組み立てていきます。

なお Vim における Pardit については 12/06 日の @ayamada さんの記事があるので併せて参照してください。
https://qiita.com/ayamada/items/ca2f4e0f6f2e7cd94831

Parinfer

ParEdit が主にショートカットを起点にしている一方で、Parinfer ではショートカットは提供されません。
Parinfer では主にインデントをベースに括弧のバランスをとってくれます。
これにより初心者だけでなく上級者にとっても Lisp のコーディングを簡略化してくれます。

Parinfer での編集例

Parinfer で使いがちな操作を編集例としていくつか挙げてみます。
なお以下は Vim と dps-parinfer を使った場合の例ですが、他エディタでも同様の編集はできるはずです。

なお dps-parinfer は拙作の Vim プラグインで、それに関して Vim Advent Calendar の方にもまとめているので、もし興味があればご参照ください。

https://zenn.dev/uochan/articles/2022-12-09-dps-parinfer

ちなみに以下の例はほとんど Parinfer のドキュメントにも載っているので、他の例も見たい場合はドキュメントも参照することをおすすめします。
https://shaunlebron.github.io/parinfer/

Slurp (フォームの飲み込み)

まずはインデントベースでの slurp です。
行頭にスペースを追加することでインデントの状態に沿って括弧の対応が自動的に更新されます。

次は慣れないと変に見えるかもしれませんが、対応する閉じ括弧を 削除 しようとした際に後ろに続く要素があった場合、それらは対応する開き括弧に飲み込まれます。
これは開き括弧が残っているため、その対応を保持しようとするための挙動です。

もし括弧の対応を消したい場合は開き括弧を削除すると綴じ括弧も消えます。
また閉じ括弧を削除しようとした際に後ろに続く要素がない場合は 閉じ括弧は消えません。 (消えると括弧の対応が崩れてしまうため)

Barf (フォームの吐き出し)

こちらもまずはインデントベースの Barf です。
行頭のスペースを消すことでインデントの状態に沿って括弧の対応が自動的に更新されます。

次はこちらも慣れるまでは変に見えそうですが、 閉じ括弧を明示的に入力 することで続く要素を対応する括弧から吐き出せます。

もちろん続く要素がない場合は閉じ括弧を入力しようとしても対応する開き括弧がないために閉じ括弧は入力されません

Insert (括弧の追加)

これはシンプルに開き括弧を入力するのみです。
そうすると続く要素が開き括弧の中に入った状態で入力されます。

以上のように Parinfer ではショートカットを必要とせず、シンプルなテキストの編集によって括弧の対応を操作することが可能となっています。

Paredit と Parinfer

Paredit も Parinfer も Structural Editing のためのものですが、どちらが優れていてどちらを利用した方が良いというものはありません。
むしろ Paredit と Parinfer は共存可能で、どちらも一緒に使っているという人も少なくないです。

Parinfer の README にも書いてあるとおり、Paredit で高度な編集を実現しつつ、Parinfer で基本的な Lisp コードの編集を簡単に行えるようにするというのが Parinfer のゴールなので、お互いに補完しあう関係であると言えます。

The hope is to make basic Lisp-editing easier for newcomers and experts alike, while still allowing existing plugins like Paredit to satisfy the need for more advanced operations.

ただ完全に個人の意見だけ述べさせてもらうと同じ操作においてはショートカットベースの Paredit にスピードの軍配はあがると思います。
ショートカットを覚える必要はもちろんありますが、カーソル位置にあまり影響されることなくキーさえ押せば良いのはやはり速いです。

Vim と Parinfer

しかし Vim のように編集するモード以外のモードを持っているエディタでは状況が異なることも確かかと考えています。
私は Vimmer なので Vim を例に出しますが、Vim では Insert (テキスト入力)モードよりも Normal (カーソル操作)モードにいる時間の方が長いです。
そして Vim の Normal モードでは多彩なカーソル移動や編集方法が提供されています。
これらと Parinfer の相性はかなり良いと思っていて、ショートカットがなくとも Vim が提供する機能を使って自然に Lisp コードを書けると考えています。

ただあくまで主観でしかないですし、私個人も Paredit(vim-sexp) と併用はしているので、参考程度にとらえていただければと思います。

最後に

私は業務で Clojure のコードを書いていますが、周りは Paredit が主で Parinfer も使っているという話をあまり聞かず、
かつ Parinfer の日本語記事もあまり見ないので良い機会と思い書いてみた次第です。

普段 Paredit を使っている方はこれを機に Parinfer も触ってみていただければと思います。

Discussion