Incremental lambda calculusとUIへの応用

はじめに

1ヶ月くらい前にpurescript-purviewというUIライブラリがリリースされました。 このライブラリは既存の仮想DOMに代わるような位置づけのライブラリとして実験的にリリースされたUIライブラリとされています。 何が実験的なのかというと、Incremental lambda calculusという概念に基づいて実装されているということでした。 一体何なんだこれは?と思ったので調べることにしました。

Incremental lambda calculus

ひとまずググってみたところ、こちらのサイトが出てきました。 上記のサイト内に論文のpdfへのリンクが貼ってありますが、「なるほどわからん」という感じです。 データベース技術を参考にした考え方っぽいことはわかりました。

さっぱりわからなかったときは実装を見たほうが早いということで、この考え方に基づいたライブラリを読むことにしました。 それがpurescript-incremental-functionsです。 purescript-purviewはこのライブラリをベースに実装されています。

コアとなる型クラスのドキュメントはこちらになります。

このソースコードから読み取れることは、「あるデータ型に対する操作を、変更増分で表現し、段階的に適用する」、というような考え方のようです。

例えば、こちらのライブラリで提供されているArrayの増分計算版であるIArray型の操作はInsertAt, DeleteAt, ModifyAtで表現するような形になっています。

次はこの考え方をどうUIに応用していくのか見ていきます。

UIへの応用

まず、前提として、purviewはこれまでの仮想DOMと同じように、状態(Modelという名前で扱われています)を受け取ってUIに変換します。そして、その状態への変更は、purescript-incremental-functionsを用いて定義された変更増分を用いて更新します。 また、purescript-incremental-functionsで提供されている型でJetというものがあります。こちらは計算対象の型と変更増分を両方もったデータ表現です。 purviewではあらゆるものをJetで表現します。purviewで提供されているUIの型もJetで記述していくような形になっています。

では、読んでいきましょう。 読むメインの場所はこのあたりになります。

まず、全体的な世界観としては、Jetで表現されたModelからJetで表現された仮想のUIのマッピングとなっていて、この関数にComponentという名前がついています。 ここで増分計算について考えます。Modelを変更したいので増分を与えるわけですが、先のComponentに現在のModelと、与えられた増分を用いたJetを渡します。 JetからJetのマッピングは増分もマッピングしてくれるため、Modelの増分から仮想のUIの増分が導きだせます。 これらのUI増分をpatchとして、現在の仮想のUIとそのpatchから生DOMに変更を与えていきます。 そして、次の計算に備えて、それぞれの増分から新しいModelと新しい仮想のUIを導き、referenceに保持し直して、1サイクル終了となります。

面白いところ

仮想DOMを読んだり実装したことがあればわかるのですが、現在の仮想DOMと新しい仮想DOMの差分計算の実装を必ず書くことになります。 よくあるkeyを与えたりするのは子要素の差分計算の効率のためです。  そして、現在の仮想DOMと新しい仮想DOMを直接比較しながら、あるいはその比較から差分表現を導き出して、生DOMに変更を適用していくような形になります。 この差分計算は通常かなり泥臭い実装になると思っています。

purviewの場合は、データの操作を増分で表現してしまい、その増分とユーザーが自ら定義した仮想のUI関数を利用して、UIの変更増分を直接導き出してしまいます。 このあたりの実装はとてもパズル的で面白く、非常にエレガントなやり方に見えました。(小並感)

一方で、増分適用できるデータ型を用意する必要がありますし、 データの変更を全て増分で与えなければいけないのも場合によっては面倒なケースがある気がしています。 例えば、IArrayを全て逆順にしたいときは全部DeleteAtしてから逆順にInsertAtするというような形でしょうか。あるいはAtomic型でくるんでまるごと置き換えるという形でしょうか。 いずれにせよ、増分の与え方は脳死状態ではできないケースがあるような気はしました。 なので、ヘルパー関数が充実していないと結構つらいケースがでてくるかもしれません。

さいごに

生DOMへの変更適用でこんな面白いやり方があるのかという発見がありました。 まだ出たばかりなのでバグがあるかもしれませんが、非常に勉強になるライブラリだと感じました。