CatyScript2.0では、「par構文」と呼ぶ構文構成素(syntactic construct)を導入するつもりです。parはparallelの略記で平行実行*1を意味します(実装上は逐次実行でも差し支えありません)。現状でも、複数のプログラム実行単位を平行に実行する構文はあるのですが、実行単位の配置がフォーク形なんです。これを図形的にもパラレルに配置するのがpar構文です。
まずは実例
Catyのコマンドは、デカルト圏*2の射としてモデル化されるので、圏論をご存知の方はそのように解釈してください。Unix流のパイプ&フィルターをご存知の方は、標準入出力を使うフィルターコマンドだと理解すればOKです。
passは何もしないコマンド、incは入力に1を足して出力するコマンド*3、sqは入力を二乗するコマンドとします。圏の恒等射に相当する総称コマンドpassは組み込みですが、incとsqは次のように定義できます。
Pythonによる実装:
# -*- coding: utf-8 -*-
# arith.py
#
from caty.command import Commandclass Inc(Command):
def execute(self, input):
return input + 1class Sq(Command):
def execute(self, input):
return input * input
コマンドの宣言:
module public; // -*- coding: utf-8 -*-/** 入力に1を足す */
command inc :: number -> number
refers python:arith.Inc;/** 入力を二乗する */
command sq :: number -> number
refers python:arith.Sq;
実行例は次のような感じ。
caty:sample> 3 | pass
3
caty:sample> 3 | inc
4
caty:sample> 3 | sq
9
caty:sample>
コマンドを配列に編成すると、フォーク配置で実行されます。
caty:sample> 3 | [pass, inc, sq]
[3, 4, 9]
caty:sample>
もし、[pass, inc, sq] がパラレル配置ならば、入力 [1, 2, 3] に対して [1, 3, 9] が出力されるはずです。そうはなってないので、やってもエラーします。
caty:sample> [1, 2, 3] | [pass, inc, sq](... スタックトレース 省略 ...)
値はnumberでなければなりません
caty:sample>
パラレル配置と同値な式を書けるには書けますが、面倒です。
caty:sample> [1, 2, 3] | [(nth 1 | pass), (nth 2 | inc), (nth 3 | sq)]
[1, 3, 9]
caty:sample>
[pass, inc, sq] がフォーク配置であることを変えるわけにはいかないので、パラレル配置であることを par [pass, inc, sq] で示します。つまり、CatyScript2.0では次のようになる予定です。
caty:sample> [1, 2, 3] | par [pass, inc, sq]
[1, 3, 9]
caty:sample>
オブジェクトに対してもpar構文が使えます。
caty:sample> {"a":1, "b":2, "c":3} | par {"a":pass, "b":inc, "c":sq}
{
"a":1,
"b":3,
"c":9
}
caty:sample>
オブジェクトに対するpar構文は、破壊的代入による部分更新のように使えます。次は、プロパティbだけを5に書き換えます。
caty:sample> {"a":1, "b":2, "c":3} | par {"a":pass, "b":5, "c":pass}
{
"a":1,
"b":5,
"c":3
}
caty:sample>
もっと簡単に書きたいなら:
caty:sample> {"a":1, "b":2, "c":3} | par {"b":5, *:pass}
{
"a":1,
"b":5,
"c":3
}
caty:sample>
デカルト圏における解釈
par構文は、圏論的に言えば射のデカルト積に過ぎません。つまり、par [f, g] は f×g のことです。集合圏における f×g の定義は次のとおり。
- (f×g)(x, y) = (f(x), g(y))
CatyScriptの構文では次のようになります。
- [x, y] | par [f, g] ⇔ [x | f, y | g]
CatyScriptの配列式 [f, g] は、射fと射gのデカルトペアリング <f, g> *4なのです。
- <f, g>(x) = (f(x), g(x))
- x | [f, g] ⇔ [x | f, x | g]
射のデカルト積とデカルトペアリングは、次のようにして相互に定義可能です。Δは対角射で、π1とπ2は射影です。
- <f, g> := Δ;(f×g)
- f×g := <π1;f, π2;g>
この事実をCatyScriptの構文で書くならば次のようになります。
- [f, g] ⇔ [pass, pass] | par [f, g]
- par [f, g] ⇔ [(nth 1 | f), (nth 2 | g)]
先ほど「パラレル配置と同値な式を書けるには書けます」と言ったのは、パラレル配置(=デカルト積)を [(nth 1 | f), (nth 2 | g)] で代用できるということです。でも、これは面倒すぎますから、組み込み構文にしたいわけね。
オブジェクト式の場合も、理論的には配列式と変わりません。オブジェクトは名前付きタプルなので、これもデカルト積の表現となっています。
par構文をMaybeモナドやListモナドと一緒に使うとどうなるか? という問題があります。これに関しては、CatyScript2.0における機能的仕様は完全に出来てますが、構文で悩んでいます。ものすごく悩んでいます。構文の方針が決まったら、ベースのデカルト圏をモナドでクライスリ拡張する方法も紹介します。