呼ばれる小さな式を組み合わせたもので、何らかの入力を受け取って出力にマップする関数を表します。idenこれは空の入力を受け取り、空の出力を生成します。2この例では、最後のSimplicity式がmain関数となっています。combinatorと呼ばれる部品で組み立てられていることが分かります。combinatorは、受け取った入力をそのまま出力するiden、外部から取得した値を出力するwitnessと組み合わせることで、あらゆるSimplicityの式の基礎となります。このサンプルコードでは、型のアノテーションを記述することで、どんなデータが式から式へと受け渡しされるかを明示しています。”1”はunitの型を示し、上記で「空の出力」と呼ぶものに該当します。“2”は1ビットを指し、0または1の値を取ります。このサンプルコードが完全に理解できなくても心配無用です。これはあくまでも、Simplicityのコードがどのようなものかを説明するための例です。本記事後半で、より実践的なプログラムを詳細に解説します。仕様を書くための言語プログラミング言語とは、極論すれば、小さな計算を組わせて大きな計算を記述するためのものです。関数を呼び出すアーキテクチャを採用しています。現在主流となっているプログラミング言語の大半は、後者のモデルです。EVMにおけるコントラクトは、キーバリュー型データストアにもアクセス可能で、明示的にデータを受け渡しせずとも複数トランザクションにまたがって状態を維持できます。(ただしBitcoin版ではビット以外の多様な入力に対応する一方、EVM版では常に256ビット単位で実行されます)。Simplicityでは、単純な操作に多量のコード記述を求めるのでしょうか?私たちがSimplicityを開発する目的は、プログラム内の関数が何を表し、どのような計算リソースを利用するかという形式仕様の記述を可能にすることです。ScriptやEVMのように、動作する言語を形式仕様として定めることも原理上は可能かもしれません。非常に複雑なため、実装もその検証も困難を極め、現実的ではありません。Simplicityは複数の関数を数学的に組み合わせた基本的なcombinatorの小集合です。そのため、言語のセマンティクスはTシャツに印刷可能なほどコンパクトです。実務上、ビット反転のような利用頻度の多いコードを逐一記述するのは煩雑なため、通常は一度記述したら、後はそれを使い回します。ビット反転のコードは既に私たちが記述し、言語にプリミティブとして搭載したので、コードを書く際は、上記コードの代わりに、jet_notショートカットを記述してください。ショートカットのjetsの詳細は後述いたします。将来的には、ほとんどの人がSimplicityで独自コードを記述する必要はなくなるでしょう。Simplicityはブロックチェーン上にプログラムを作成するための基礎となりますが、あくまでも基礎です。複雑なコードは、より高級な言語で記述し、それが正しく動作するという証明とともに、Simplicityコードへとコンパイルされるようになるでしょう。入力値と出力値を1:1で結びつける関数は、数学的に1つしかないため、Simplicityでプログラムを書くメリットは一見なさそうです。ところが、Simplicityでの記述は有益なだけでなく、ブロックチェーン上で関数を柔軟に記述するには必然なのです。Simplicityでなければいけないのでしょう?ポイントは2つあります。1つはSimplicityプログラムにはholeと呼ばれる「穴」があり、この穴はコインが消費されるときにしか埋まらないことです。(副作用)を通して、ブロックチェーンデータの読み取りや、早期終了など純粋な数学的関数では実現できない動作を可能にすることです。Holeを指定する方法としては:disconnectおよびwitnessコンビネータの2つがあります。disconnectは少し細かい動作をするので、詳細は過去の解説をご参照ください。(電子署名、ハッシュのプリイメージ、または特定の署名鍵)。対応法も2つあります。(別記事で解説予定)、もう1つはassertionです。Assertionはプログラムの実行を停止します。Scriptにおいては、VERIFYオペコードがassertionに利用され、例えば不正な署名やデータを検知するとプログラムを終了させます。EVMでは、同じ目的でSTOPオペコードが使われます。ここまで読んでいただけたら、一見単純な入力と出力をもつプログラムが有益な計算を行う仕組みを理解できたのではないでしょうか。Witnessがプログラムへの入力、Assertionが成功・失敗という形でのプログラムの出力になります。1前例と同様、プログラムを下から上に見ていきます。型は入力と出力のデータ型を示します。”1”型は単一値で、特に情報を持ちません。”2”型は2つの値を取ることができるため1ビットを表し、”2^32”型なら32ビットの文字列を表します。あることがわかります。上の行の定義から、cp3自体もpr1とjt2の組み合わせであることがわかります。2つの式を受け取り、最初の式の出力を次の式に入力して評価します。pairは2つの式を受け取り、左側に1つ目の式の出力、右側に2つ目の式の出力を持つペアを出力する新たな式を返します。witnessは入力を受け付けず、出力は多態性を持つためプログラムの動作に必要な型として解釈されます。出力値はプログラム実行時に提供されます。jet_eq_32はjetと呼ばれる、より大きなSimplicity式を短縮して1つのコンビネータとして表現したものです。置き換えられた元の式はspecificationと呼ばれます。Simplicityのインタプリタがjetを評価する際は、specificationを実行、あるいは全く同じ挙動をする最適化された機械語を実行することになります。jet_eq_32は2つの32ビットの値を入力として受け取り、2つの値が同一なら1、異なれば0という1ビットの値を返します。jet_verifyもjetです。1ビットの入力を受け取り、それが0であればプログラムを強制終了します。難しかったかもしれませんが、Simplicityのコードを読み解くことで、一見単純な機能でも明示的に記述すると複雑に見えることを実感いただけたのではないしょうか。この複雑性は、実行中の処理を忠実に反映したものです。仕様を記述するための言語であるSimplicityは、すべての処理を明示的に指定することで、数学的なモデリングや必要な性質の証明を行います。これにより、堅牢性が保証された一連の処理を、アプリ開発者が安心して再利用できるようになります。Simplicityには本記事で解説した以外にも、複数のコンビネータとjetがあります。それらについては、今後、別の記事で紹介させていただきます。言語開発の進捗にあわせ、より現実的なコード例や、プログラムの性質を証明するとはどういうことかなど解説する予定です。いうコンセプトを取り上げ、同一式という概念そのものについて詳細に説明します。Simplicityに関する質問やフィードバックは、GitHub上でSimplicityに関するディスカッションからお寄せください。ブログ記事の更新情報は、Twitterの@blksresearchでお知らせします。