LPScript

ブラウザで動く画面を書くための、アクタを持つ関数型 Smalltalk

メッセージはメソッド呼び出しとして届く

アクタに届いたメッセージは、同じ名前のメソッドの呼び出しになります。メソッドは次の状態を返します。受信ループはありません。この設計により、ランタイムは処理を途中で止めて再開する仕組み(fiber やジェネレータ)を必要とせず、待つ処理は JavaScript の await で書けます。

再描画の範囲は指定しない

ハンドラが返した状態が前の状態と同じオブジェクトなら描き直さず、別のオブジェクトなら描き直します。判断はランタイムが行い、プログラムには再描画の条件を書きません。

小数は Decimal

ソースに 1234.50 と書くと Decimal になります。二進の浮動小数点ではありません。割り切れない除算はエラーで、丸めるときは桁と方向を指定します。業務システムで金額の計算を誤らないための設計です。

HTML はデザイナが書いたものを使う

一覧の行やダイアログは、デザイナが HTML に置いた見本を複製して使います。プログラム側に HTML は書きません。HTML に無いセレクタをプログラムに書くと、コンパイルエラーになります。

用途

ブラウザで動く画面です。一覧、検索、明細、編集と保存、画面間の値の受け渡し、HTTP と WebSocket による通信、毎フレーム描き直すアニメーションが書けます。

仕組みは一つです。状態はアクタが持ちます。ボタンのクリック、通信の応答、アニメーションのフレームは、全部メッセージとしてアクタに届きます。描き直すかどうかは、状態が変わったかどうかで決まります。一万行の一覧も、ブロック崩しも、canvas のシューティングも、この仕組みだけで書いてあります。ゲーム用に追加した機能はありません。

業務データの扱いは既定で正しくなるようにしてあります。金額は Decimal、日付は暦の日付、JSON の数値は桁を落としません。

Actor subclass: #Counter fields: (count).

Counter class >> init: n = Counter fields: { count: n }.

Counter >> inc = self with: { count: count + 1 }.
Counter >> get = self reply: count.

c := Actor spawn: (Counter init: 0).
c tell inc.
(c ask get) forced printNl.          "1"

Lambda Prelude と設計を共有しています。Lambda Prelude はサーバ側の常駐サービスを書くための言語で、OCaml 5 で作られています。LPScript はその移植ではなく別の言語で、共通なのは、値は変化しない、継承ではなくプロトコルを組み合わせる、nil の代わりに Maybe を使う、という三つの設計です。ランタイムに共通部分はありません。

コンパイル時に検出されるもの

ハンドラの無いメッセージ。 Counter に increment というハンドラが無ければ、c tell increment はコンパイルエラーです。ask の結果の型は、返事をするハンドラの型で決まります。ActorRef[a] としか型の付いていない参照への送信もコンパイルエラーです。照合する相手のハンドラが無いためです。

HTML に無いセレクタ。 Html clone: '#lines tr' の '#lines tr' は、モジュールが page: で指定した HTML と照合します。

become: でのメッセージの欠落。 別のクラスに置き換わったとき、参照の型が要求するメッセージを受け付けられなくなっていれば、コンパイルエラーです。

別のアクタへのブロックの受け渡し。 ブロックは作られた場所の変数を参照しているので複製できません。アクタ間で渡す値は複製可能でなければならないため、コンパイルエラーです。

金額、日付、JSON の扱い

1234.50 は Decimal です。割り切れない除算はエラーになり、丸めるときは桁と方向を指定します。

Date は暦の日付で、時刻もタイムゾーンも持ちません。31 日の一か月後は翌月の末日です。

JSON の数値は届いた文字列のまま保持するので、1234567890123456789.12 はサーバと往復しても同じ値です。

実行環境

ブラウザで、普通の ES モジュールとして動きます。一つの画面は一つの .lps ファイルと、そこから import する部品でできています。ビルドは画面ごとに行います。280 行の受注画面の型検査にかかった時間は 0.000 秒と表示されました(計測の分解能未満)。

一つの画面が一つのプログラムです。 画面と画面が共有するのは、前の画面が書いて次の画面が一度だけ読む文字列だけです。生きたアクタや共有オブジェクトは渡しません。この設計により、一人が受け持つ範囲とコンパイラが検査する範囲が一致します。画面を一人一つずつ割り当てることができ、一つの画面を変更しても他の画面のビルドし直しは不要です。

重い処理は Worker spawn:on: と書けば別のスレッドで動きます。アクタへの参照はスレッドの位置を持たないので、呼ぶ側の書き方は変わりません。

ライセンスとお問い合わせ

LPScript は プロプライエタリソフトウェアであり、すべての権利は 合同会社 Lambda に帰属します。LPScript の複製・改変・再配布には、合同会社 Lambda による書面での事前許可が必須 です。OSS ではありません。

バイナリ(コンパイラ lpsc、言語サーバ、ランタイム、エディタ拡張)は 無償・無保証・現状有姿 (as-is) で提供します。評価・利用は すべてご自身の責任 で行ってください。特定用途への適合性は保証しません。別途契約しない限りサポートは提供せず、利用に起因する一切の損害について責任を負いません。

ソースコード は NDA を締結したパートナー企業にのみ開示します。この NDA および付随する個別契約が、ライセンス本文で要求される「書面での事前許可」にあたります。ソース開示は 有償案件(共同開発・カスタマイズ・統合)とセット であり、ソース単体での販売は行いません。

業務画面の開発や本番運用での LPScript 利用をご検討の場合は、お気軽にご相談ください。主に以下の 3 つの形態でご一緒します。

ご相談は 合同会社 Lambda までお寄せください。