もうすぐKahua 1.0がリリースされるらしい

要約:

イーガンっぽい部分要約:

  • HTTPのウェブサービスは、可能な限り、多世界解釈的なアクセス構造に耐えられる必要がある。
    • 「オラクル」「ひとりっ子」、「無限の暗殺者」もそうだが、ここはやっぱり「宇宙消失」のシチュエーションがぴったり来る。
      • ……と思っていたが、あとで考えたら、それほどぴったりでもなかった。「オラクル」的な歴史構造が一番それっぽい?
  • そこら辺(多世界解釈的アクセス構造)を限界まで考えていくと、やっぱり「(部分)継続をファイルに保存する」機能が欲しい。
    • 「(部分)継続をファイルに保存する」とか、その辺を考えると、「順列都市」のコピー人格の実行を連想。
  • 継続をファイルに書き出す場合、継続内の外部(データストレージや入力その他)とのつながりを抽象化しておく必要がある(portよりも更に)。
  • HaskellみたいなIO構造が必要?

ゲーマー用の要約:

  • ANOSは継続。A.D.M.Sも継続。第三視点も継続。セーブ&ロードも継続。


最初に書いておくと、自分はあまりKahuaをまじめにいじってないので(いじったのはかなり昔)、書いている内容が正しいという保証は無し。
また、分かりにくい記述があちこちにある為、あとで文章を書き直した方がいい気がする。


Kahuaは、ぶっちゃけて言えば、次のようなCGIコード(schemer以外の人が読む事も考えて、疑似Cコードで書きます)を、

/* サンプルコード1 */
/* 掲示板っぽいCGIを想定。
 * 最初のアクセスで、通常画面とpostフォームを表示し(default動作)、
 * postフォームに記述して書き込むと
 * 「この内容で書き込んでいいですか?」画面が出て(confirm画面)、
 * そこで確認ボタンが押されると
 * 実際にその内容をデータストレージに書き込むと同時に
 * 完了画面へとリダイレクトを行い(submit)、
 * 完了画面を表示する(done画面)、
 * という一連の動作を行う。 */
int main () {
  char *errormsg;
  CgiParams *params = get_cgiparams();

  switch (params->cmd) {
    case done:
      /* 完了画面を表示するだけ */
      print_done_html(params);
      break;
    case submit:
      /* post内容を検証する */
      if (errormsg = is_invalid_posted_data(params)) {
        print_error_html(errormsg);
        break;
      }
      /* POSTされたデータをストレージに書き込む */
      store_posted_data(params);
      /* doneへとリダイレクトさせるレスポンスを出力して返す */
      print_http_location("http://.../hoge.cgi?cmd=done");
      break;
    case confirm:
      /* post内容を検証する */
      if (errormsg = is_invalid_posted_data(params)) {
        print_error_html(errormsg);
        break;
      }
      /* post内容を表示し、これでいいかどうかの確認画面を表示させる */
      /* この確認画面には、「ok」「ng」ボタンがあり、
       * 「ok」ボタンを押すとsubmitに進み、
       * 「ng」ボタンを押すとdefaultに戻るものとする。 */
      /* 「ok」ボタンには、hiddenでpostされた内容のコピーが含まれている。 */
      print_confirm_html(params);
      break;
    default:
      /* 通常画面とpostフォームを表示するだけ */
      print_default_html(params);
      break;
  }
  return 0;
}

次のような感じに書けたらいいな、という発想を具現化したものだと言える。

/* サンプルコード2 */
int main () {
  char *errormsg;

  while (1) {
    /* 通常画面とpostフォームを表示し、postフォームの内容を受け取る */
    PostedData *data = print_default_html();
    /* post内容を検証する */
    if (errormsg = is_invalid_posted_data(data)) {
      print_error_html(errormsg);
      continue;
    }
    /* post内容を表示し、これでいいかどうかの確認画面を表示させる */
    /* この確認画面には、「ok」「ng」ボタンがあり、
     * 「ok」ボタンを押すとsubmitに進み、
     * 「ng」ボタンを押すとdefaultに戻るものとする。 */
    PostedData *data2 = print_confirm_html(data);
    if (data2->confirm != "ok") {
      /* 確認画面で「ok」じゃない方が押されたので、最初に戻る */
      continue;
    }
    /* (dataは、既に内容検証に通っているので、
     *  サンプル1とは違い、二重に検証する必要は無い。)
     * (サンプル1では、確認画面を経由した時点で、最初にpostされた
     *  paramsは失われてしまっているが、このサンプル2では、
     *  まだ変数dataに保持されているので、参照が可能。)
     * (「サンプル1でも、paramsの内容は同じじゃねえの?」と思った人は
     *  セキュリティ意識が甘い。確かに通常は同じだが。) */
    /* POSTされたデータをストレージに書き込む(※副作用を伴う動作) */
    store_posted_data(data);
    /* doneへと明示的にリダイレクトさせる
     * (副作用を伴う動作を、ブラウザの「戻る」「進む」で
     *  二重に実行してしまわないようにする為、これが必要になる) */
    print_redirect_to_next();
    /* 完了画面を表示するだけ */
    print_done_html();
    /* 最初に戻る */
  }

  /* NOTREACHED */
}

(他にも補助的な機能が色々とあるが、一番メインになるのはこの部分だと思う。)


で、これを実現する為に、KahuaKahuaと同様の機能を提供するフレームワーク(他にも何個かある)は、部分継続や、CPS変換やら、パラメータのセッションへの保存やら、色々とややっこしいテクニックが使われている。
大まかでいいなら、何も考えずに記述しても特に問題は無いが、きっちり隅から隅まで問題なく記述しようとすると、セッションの破棄タイミングや、副作用のタイミング等を考えないといけない為、通常のCGI作成とは違った部分で脳味噌を使う必要がある。
(とは言え、慣れの範疇に入ると思われるし、非KahuaCGIでも副作用のタイミングは結局、考えなくてはいけない。考えていない人は無意識の内にそれを解決しているか、ただ単に職務怠慢なだけだ。)


ところで、ウェブブラウザには「別のページとして開く」「別のタブとして開く」という機能がついている。
これを利用してページを複製すると、「okを選んだ後のページ」と「ngを選んだ後のページ」を同時に見る事が可能となる。
また、この機能を使わなくても、ブラウザの「戻る」「進む」を使えばほぼ同等の事が可能となる。
これを、実際のコードと対応させて考えてみる事にする。
まず、先のサンプル1の方では、ページ単位でコードが分岐している為、「okを選んだ後のページ」も「ngを選んだ後のページ」も、普通に並列に存在している。実に当たり前だ。
しかし、サンプル2の方では、二番目のif文とその前のところ、「PostedData data2 = print_confirm_html(data);」「if (data2->confirm != "ok")」ここで、未来が分岐してしまう。
このサンプルコードでは「ng」を押された方の未来は最初に戻るだけだが、「ok」を押しても「ng」を押してもそれぞれ別の画面へと遷移していくコードは容易に書けるし、そのような場合でも問題なく動作するのか?


結論から行くと、Kahuaなら問題なく動作する。
(しかし、同様のフレームワークの中には、このように動作しない不完全なものもある。せめて「戻る」ぐらいは対応しといてほしい、某フレームワーク!)
これは、Kahuaが、セッション毎アクセス毎に「継続ポイント」を作成し、過去の継続ポイントを(充分古くなってもうアクセスが無いだろうと判断されるまでは)ずっと保持する事によって実現している。
そして、「ok」「ng」でそれぞれ分岐した両方で、新しい「継続ポイント」が生成され、別々の未来として独立に先に進む事になる。

(これ以上の詳しい原理は説明すると長くなるので省略。興味を持った人はKahuaのサイト等を見て自分で調べましょう。)


この「継続ポイント」は、要するにゲームの「セーブポイント」とほぼ同様に機能する。
つまり、「セーブ可能なポイント」イコール、サンプル2のprint_*()関数イコール、ウェブブラウザに何かが表示されるポイントイコール、「別のページ/タブで開く」「戻る」「進む」が選べるポイント、という事になる。
要するに、選択肢が出現する毎に毎回新しいファイルに自動セーブされているのと同じ感覚になる。


しかし、「継続ポイント」が「セーブ」とは違うのは、「継続ポイント」は所詮プロセス内の存在なので、プロセスが終了してしまうと失われてしまうし、ファイルに書き出す事が出来ない(クイックセーブ的存在?)。
この機能が個人的に、どうしても欲しい。
過去の履歴として、継続ポイントそのものをログファイル等に残せるようにできれば、ウェブアプリ世界は、初期状態からの完全な履歴を残す事が可能になる。
しかも、ウェブアプリ世界はその成り立ち故に多世界解釈なので、多世界解釈の(アクセスされた範囲のみでの)履歴となる。これはイーガン好きなら見てみたい世界だ。
しかし、素のschemeでは環境を握ってしまう部分が多い為、もう少し抽象化の度合いを進めないと(副作用の除去やVM化等?)実現できなさそうなのが残念だ。
とは言え、実際のウェブアプリでは、全てをログファイルに残す意味は薄そうではあるが。
ウェブアプリではなく、もっとイーガンっぽい用途の為に使う必要がある。継続のシリアライズは。


とにかく、そんなこんなでKahua 1.0がリリースされたら、またいじりはじめてみようと思っている。


他の人も、興味を持ったら、試してみませんか?
scheme/S式は初めの内は、見た目が異様に見えるかもしれませんが、構文自体は見ての通り、これ以上無いぐらいに簡潔なので、間違った記述をしてしまう事も他の言語より少ないと思います、自分は。
ただ、Kahuaは、常駐し、メモリを大量に消費するので、共用サーバには不向きですが。