ほぼ1年後、これに戻ると、投稿する前にいくつかの重要な研究を見逃していたことに気付きました。
Jotは、コンパクトなゲーデル番号で表すことができる2つの比較的単純なコンビネーターB&Xで、私が求めていたものの案に合うようです。
私は彼のリファレンス実装をPythonで単純化しました:
def S(x): return lambda y: lambda z: x(z)(y(z))
def K(x): return lambda y: x
def X(x): return x(S)(K)
def B(x): return lambda y: lambda z: x(y(z))
def I(x): return x
def J(n): return (B if n & 1 else X)(J(n >> 1)) if n else I
J(n)は、ゲーデル番号nで表されるプログラムを示すビルドアップ関数を返します。
B(チャーチ符号化乗算と同等)は、機能アプリケーション(括弧)の機能を果たし、単一基底IotaコンビネーターXのS / K半分を分離できます。
私が(ほぼ)恥知らずに、この言語の発明者であるChris BarkerのWebサイトから2000年頃に盗んでいる、この言語のいくつかの重要な特性があります。
Jotは通常の構文言語ですが、チューリング完全です。J(n)の実装から、ホスト言語が末尾再帰をサポートしている場合、ビット文字列プログラム形式を解析するために必要なスタックスペースがないことがわかります。
チューリング完全性の証明は、Chrisのサイトにもあり、SおよびKコンビネーターを使用して既知のチューリング完全な組み合わせロジックを実装しています。
K ==> 11100
S ==> 11111000
AB ==> 1[A][B], where A & B are arbitrary CL combinators built up from K & S
Jotには構文エラーはありません。Goedel番号nが与えられたすべてのプログラムが有効なプログラムです。これは、構文解析を単純化するだけでなく、理論的には、不正なプログラムをスキップする必要のあるチューリング完全なエンコーディングよりもJotをはるかに節約できるため、私自身の研究にとっておそらく最も重要な側面です。
Jotで関数のコルモゴロフの複雑さを見つけるという半決定的な問題を、総当たりで「解決」するためのツールをいくつか書きました。プログラマーに依存して関数のマッピングの非常に特徴的なトレーニング例を指定し、すべてのトレーニング例が一致するまですべてのJotプログラムを列挙し、最後に、見つかった関数が元の冗長実装と等しいことの証明を試みます。
現在のところ、私の限られたリソースで最大40ビットまでしか機能しません。私はSATソルバーで書き換えを試みて、はるかに大きなプログラムを学習しています。バインドされたネストされたクロージャーをブール式としてアンロールする方法を知っている場合は、私の新しい質問を手伝ってください。
ここで、簡潔さで知られているJohn TrompのBinary Lambda Calculusとの興味深い比較について説明しますが、構文エラーの可能性があるという問題があります。次のプログラムは、私の学習プログラムによって数秒で生成されました。
Function Jot Binary Lambda Calculus |J| |B|
--------|----------|--------------------------|---|---
SUCC J(18400) "000000011100101111011010" 15 24
CHURCH_0 J(154) "000010" 8 6
CHURCH_1 J(0) "00000111010" 1 11
CHURCH_2 J(588826) "0000011100111010" 20 16
IS_ZERO J(5) "00010110000000100000110" 3 23
MUL J(280) "0000000111100111010" 9 19
EXP J(18108) "00000110110" 15 11
S J(8) "00000001011110100111010" 4 23
K J(4) "0000110" 3 7
AND J(16) "0000010111010000010" 5 19
OR J(9050) "00000101110000011010" 14 20
私自身の実験から、Jotがより小さなプログラムにつながるという仮説は、私のプログラムが単純な関数を学習し、それらを構成し、改善された天井からより大きな関数を学習するにつれてゆっくりと確認されています。