HigherLogicsは私のブログであり、私はこの質問の調査に多くの時間を費やしてきました。制限は確かに型構築子の抽象化、別名「ジェネリックスのジェネリックス」です。MLモジュールを模倣するためにできる最善のことのようであり、ファンクターには少なくとも1つの(セミセーフ)キャストが必要です。
基本的には、抽象型と、その型で動作するモジュール署名に対応するインターフェースを定義することになります。抽象型とインターフェースは、私が「ブランド」と呼ぶ型パラメーターBを共有しています。ブランドは通常、モジュールインターフェイスを実装するサブタイプにすぎません。ブランドは、渡されたタイプがモジュールによって期待される適切なサブタイプであることを保証します。
// signature
abstract class Exp<T, B> where B : ISymantics<B> { }
interface ISymantics<B> where B : ISymantics<B>
{
Exp<int, B> Int(int i);
Exp<int, B> Add(Exp<int, B> left, Exp<int, B> right);
}
// implementation
sealed class InterpreterExp<T> : Exp<T, Interpreter>
{
internal T value;
}
sealed class Interpreter : ISymantics<Interpreter>
{
Exp<int, Interpreter> Int(int i) { return new InterpreterExp<int> { value = i }; }
Exp<int, Interpreter> Add(Exp<int, Interpreter> left, Exp<int, Interpreter> right)
{
var l = left as InterpreterExp<int>; //semi-safe cast
var r = right as InterpreterExp<int>;//semi-safe cast
return new InterpreterExp<int> { value = l.value + r.value; }; }
}
}
ご覧のとおり、型システムにより、式タイプのブランドがインタプリタのブランドと一致することが保証されるため、キャストはほとんど安全です。これを台無しにする唯一の方法は、クライアントが独自のExpクラスを作成し、Interpreterブランドを指定する場合です。この問題を回避するより安全なエンコーディングもありますが、通常のプログラミングには扱いにくいです。
後でこのエンコーディングを使用し、MetaOCamlで記述されたOlegの論文の1つから例を翻訳して、C#とLinqを使用しました。インタプリタは、ASP.NETのサーバー側またはJavaScriptとしてクライアント側でこの埋め込み言語を使用して記述されたプログラムを透過的に実行できます。
インタプリタに対するこの抽象化は、Olegの最終的なタグレスエンコーディングの機能です。彼の論文へのリンクはブログ投稿にあります。
インターフェイスは.NETではファーストクラスであり、インターフェイスを使用してモジュール署名をエンコードするため、モジュールとモジュール署名もこのエンコードではファーストクラスです。したがって、ファンクターは、モジュール署名の代わりにインターフェースを直接使用します。彼らはISymantics<B>のインスタンスを受け入れ、それへの呼び出しを委任します。