「Lispが安定してることがアピールポイントか」に対しての考察

Table of Contents

背景

vim-jpラジオのEmacs回に出演しました - Zenn を書いたのだが、conao3から「n年前のコードを動かすためにはn年成長しなければ良い、そこはアピールポイントにならないという気持ちではある」という指摘を受けた。 その過程でvim-jpの #random チャンネルで議論になった。 人によってかなり前提や置かれている状況が違うので、自分が想定していた条件や「Lispが安定している」についての理解と主張を文書という形でまとめておく。

免責事項

この記事は個人ブログに書いているので、あくまで個人の理解や見解をまとめている。 その為、技術的に間違えていることが書かれている可能性があるので要注意。

platform想定読者目的
Zenn不特定多数対外的な宣伝目的
takeokunn.org特定少数個人的なメモ

また、特に断りがなければ以下を想像しながら書いている。 本当はGoやRustも含めて書きたかったが経験が浅いので今回は除外する。

  • Lisp: Common Lisp
  • 通常の言語: PHP, NodeJS

対象箇所

こまもかさんからのお便り から抜粋。

Q. Emacsといえば設定をEmacs Lispという専用のLispで行ったり、他のエディタよりLisp系言語のサポートが手厚い事が有名だと思います。 かく言う僕もCommon Lispを書くためにEmacsを始めたのですが、皆さんの思うLispの魅力などについてお聞きしたいです。

A. Lispの魅力についての外観をつかみたいなら ハッカーと画家 コンピュータ時代の創造者たちLand of LispA Road to Common Lisp を読むことをお勧めします。 Lispにもっと踏み込みたいなら On LispLET OVER LAMBDA もお勧めです。

僕個人としての魅力は、Lisp自体の言語仕様が変わることはなく、Lispの言語仕様の上にmacroや関数を積み上げているので30年前のコードベースも余裕で動くことです。 ソフトウェアを開発していると後方非互換の回し車に常に追われており、頻繁なバージョンアップを余儀なくされます。 phpプロジェクトは1年塩漬にされているとさまざまな依存関係のせいで動かないことが多々あります。

当初の自分の主張

プログラムを書くにはざっくり4種類の層がある。

  • 言語自体の構文や処理系
  • 処理系が提供している標準関数やpackage
  • 外部packageやフレームワーク
  • ユーザーが書いているコード

主観の各言語ごとの変化の度合のマトリックスは以下。(×→変化なし、○→変化量が多い) 一度書いたコードが未来の処理系でも過去の処理系でも動くかどうかということを想定している。 「言語自体の構文や処理系」を変更するとすべてを変更する必要があるように、ステップが下にいくにつれて影響度合いが大きくなる。

LispNodeJSPHP
言語自体の構文や処理系×
処理系が提供している標準関数やpackage
外部packageやフレームワーク

実際のプロジェクトはほぼ以下の2種類のパターンで構成されている。 Emacs Lispの場合はフレームワークまで含めてなのでBを指す。

  • A. 言語自体の構文や処理系 + 処理系が提供している標準関数やpackage + ユーザーが書いているコード
  • B. 言語自体の構文や処理系 + 処理系が提供している標準関数やpackage + 外部packageやフレームワーク + ユーザーが書いているコード

また、世の中にはお作法の良いプロジェクトと悪いプロジェクトの2種類がある。 作法の良いプロジェクトはインストール手順や依存バージョンが明瞭に明記されており、高確率でストレスなく入ってくれるものを想定している。 作法の悪いプロジェクトはドキュメントも何もない、何年もメンテナンスされていない、経験が浅い人が作ったようなものを想定している。

お作法が悪いものをA’とB’とすると、個人的な安定度合の感覚のマトリックスは以下。(×→安定しない、○→安定する) 安定度合とは、Goの古いコードが動かなくなることはほぼない理由 に書かれているような、長期間塩けっしても動いてくれるといったことを想定している。

LispNodeJSPHP
A
A'
B
B'××

Common Lispで有名なマクロユーティリティ(外部package)のalexandriaは数十年コアコードに変化はないが、ASDFで簡単にインストールが可能。 後方非互換の回し車から逃れる - A Road to Common Lisp にも一節があり、この一節には自分の過去の業務経験からも共感できる。

もしあなたが他の言語から来たのなら、あなたが言語実装やライブラリを「アップデート」して色々壊れる、ということがあったのではないでしょうか。あなたが10年前に書いた Ruby コードを、最新バージョンの Ruby で走らせようとしたら、おそらくアップデートにはある程度の努力が必要でしょう。私の現在の仕事は Scala なのですが、あるライブラリの最後の Github 上の更新が2,3年前だったなら、私はすぐに、私の側でかなりの量の変更をしないと動かないだろうな、と想定します。この 後方非互換の回し車 こそが、私達が毎日扱っているものであり、そして多くのモダンな言語における現実 なのです。モダンな言語には、確かに他の言語よりいいところもあるのですが。

Common Lisp を学ぶと、このようなことは通常ありません。この投稿の次の節で、私は1990年に書かれた本を推薦するつもりです。あなたはその本のコードを、変更することなく、先月にリリースされた Common Lisp 実装で走らせることが出来ます。 後方非互換の回し車 で何年もジョギングしないと、私は書いたコードが20年後も十分動くと期待できることがどれだけ 安心 かを言うことが出来なかったでしょう。

conao3の主張

「n年前のコードを動かすためにはn年成長しなければ良い、そこはアピールポイントにならないという気持ちではある」やそれに続けての主張について列挙すると以下。

  • そもそも10年間何も開発しなければ良いだけなのでは
  • ユーザーが少ないからニーズが少ないだけなのでは
  • 特にEmacsの場合は破壊的変更を極端に避ける傾向があり、引数が増えるなどワークアラウント的な対応が多くなっている
  • 塩漬けについてはその環境を再現するということだけで達成できて、塩漬けしたものが現代のランタイムでそのまま動くというのは運がよいだけもしくはランタイムが単に変化してないだけ
    • Nixのようなエコシステムで実現可能なのでは
  • エコシステムの設計までされているGoやRustでも良いのでLispだからという訳ではないのでは

「conao3の主張」に対しての解答

そもそも10年間何も開発しなければよいだけなのでは

S式で自分で構文を作れるLispとphp-srcに手を入れなくちゃいけないPHPだと状況が違いそう。 10年間何も開発しなくてもユーザー側に不満が溜らないかどうかの差はありそう。

ユーザーが少ないからニーズが少ないだけなのでは

それはそう。JavaScriptはユーザーのニーズに答え続けているから複雑になっている。 ユーザー側でニーズが満たせるかどうか、ユーザーのニーズが満たされるか、その変更が自分にとって都合が良いかどうかは人によって違いそう。

塩漬けについてはその環境を再現するということだけで達成できて、塩漬けしたものが現代のランタイムでそのまま動くというのは運がよいだけもしくはランタイムが単に変化してないだけ

事前知識のない状態でB’の状態のコードを渡された時に、GolangプロジェクトとPHPプロジェクトだとどちらが動作させやすそうかで言うとGolangと答える人が多いと思っている。 なんとかして動重ないといけない状況で動かしやすそうな言語はある。 Lispプロジェクトが動かしやすいのは昔ながらのプロジェクトが多く、単に依存が少ないだけというのもある。

特にEmacsの場合は破壊的変更を極端に避ける傾向があり、引数が増えるなどワークアラウント的な対応が多くなっている

これはそう。いったんdeprecatedにして数個先のバージョンで削除するみたいな対応もありがち。 破壊的変更を避けると全体の開発速度が落ちるのはそう。 それを良しとするかどうかは文化の問題であり、それを好むかどうかは個人の好み。

エコシステムの設計までされているGoやRustでも良いのでLispだからという訳ではないのでは

世の中にある大量のプログラミング言語の中での程度の問題だと思っている。 自分の肌感覚だとLispは簡単な部類だと思っている。

個人的な結論

「Lispが安定しているかどうか」で言うと、これは確実に真だと思っている。 「安定していることはアピールポイントにならない」というのは完全に個人の好みだと思っている。 ユーザーが少ない、用途が限られているが故の安定だとしても意味があるのではないだろうか。