IConvertibleを削除する
「簡単な部分」から始めましょう:を削除しIConvertible
ます。これが必要な理由は、このコードをすべての型で機能させたいためです。つまり、特定のメンバー(Implies
)があることに常に影響を与えることができるとは限りません。あなたがやりたいのは、彼らがC ++で呼んでいるものです:テンプレートの特殊化ですが、残念ながらC#では(まだ?)利用できません:
static bool Implies<T>(T premise, T conclusion) where T : IConvertible
{
var x = premise.ToUInt64(null);
return x == (x & conclusion.ToUInt64(null));
}
static bool Implies<T>(T premise, T conclusion) where T : Foobar
{
// other fancy logic
}
// and so on
これを解決する最も簡単な方法は、マルチメソッドを使用することです。これには「dynamic」キーワードを使用できます。
public partial class Implications
{
internal static bool CheckImplies<T>(T lhs, T rhs)
{
return Implies((dynamic)lhs, (dynamic)rhs);
}
public static bool Implies(int lhs, int rhs)
{
return lhs == (lhs & rhs);
}
// your other implies thingies implement this same partial class
}
public static partial class LogicExtensions
{
public static bool Implies<T>(this T premise, T conclusion, Paradox<T> predicate = null)
{
if (null == predicate)
return conclusion.Infers(premise, Implies);
if (Infers != predicate)
return predicate(premise, conclusion);
return Implications.CheckImplies(premise, conclusion);
}
public static bool Infers<T>(this T premise, T conclusion, Paradox<T> predicate = null)
{
if (null == predicate)
return premise.Implies(conclusion, Infers);
if (Implies != predicate)
return predicate(premise, conclusion);
return Implications.CheckImplies(premise, conclusion);
}
}
また、「3番目の」メソッドがある場合は、単にそれを呼び出すことができます
私は奇妙な再帰的定義を数分間見てきましたが、それは私にはあまり意味がありません...とにかく3番目のヘルパーメソッドがある場合は、それを直接呼び出してみませんか?:-)
public static bool Implies<T>(this T premise, T conclusion)
{
return Implications.CheckImplies(premise, conclusion);
}
public static bool Infers<T>(this T premise, T conclusion)
{
return Implications.CheckImplies(conclusion, premise);
}
not(not(T))問題
上記は私にはあまり意味がありませんでしたが、型システムと言語を使用して少し手助けするのは完全に合理的だと思います。まあ、確かにあなたはそれをすることができます、そしてこれは私がそれをする方法です... :-)
ジェネリックを使用して「Not」クラスを導入しましょう。
public class Not<T>
{
public Not(T val)
{
this.not = val;
}
internal T not;
}
ここでNot>の状況が発生した場合は、提供します。それ以外の場合は、直接使用します。まあ、私たちはいくつかの拡張機能でそれを非常に簡単に行うことができます:
public static T Optimize<T>(this Not<Not<T>> var)
{
return Optimize(var.not.not);
}
public static T Optimize<T>(this T var)
{
return var;
}
それをテストするために、あなたは同様のことをすることができます:
var val = new Not<Not<int>>(new Not<int>(2));
var result = val.Optimize();
これは、過負荷解決によって正しいOptimize呼び出しが選択されるため、機能します。これにより、Not>>>>をT値などに最適化できます。
'Not'をラッパークラスでラップしてから、型システムを有利に使用するため、これも機能します。
元の問題に戻る
「Implies」と「Infers」を直接評価する代わりに、一時オブジェクトを使用して邪悪な作業を行ってみませんか。演算子のオーバーロード(正確には暗黙的な変換)を使用して、暗黙と推論の関係を指定できます。唯一の欠点は、拡張メソッドに制限があることです。
C#演算子のオーバーロードは、最適な方法を選択します。前者の場合、これは完全に一致し、後者の場合、メソッドは暗黙的に変換され、その後Evaluateが呼び出されます。言い換えれば、評価が怠惰になるという理由だけで、スタックオーバーフローは発生しません。コードの準備はできましたか?:-)
public class Implies<T>
{
public Implies(T premise, T conclusion)
{
this.premise = premise;
this.conclusion = conclusion;
}
public T premise;
public T conclusion;
public static implicit operator Infers<T>(Implies<T> src)
{
return new Infers<T>(src.conclusion, src.premise);
}
}
public class Infers<T>
{
public Infers(T premise, T conclusion)
{
this.premise = premise;
this.conclusion = conclusion;
}
public T premise;
public T conclusion;
public static implicit operator Implies<T>(Infers<T> src)
{
return new Implies<T>(src.conclusion, src.premise);
}
}
public static partial class LogicExtensions
{
public static Implies<T> Implies<T>(this T premise, T conclusion)
{
return new Implies<T>(premise, conclusion);
}
public static Infers<T> Infers<T>(this T premise, T conclusion)
{
return new Infers<T>(premise, conclusion);
}
}
public class Foo
{
// The things you wish to implement :-)
public static bool Evaluate(Implies<int> impl)
{
return impl.premise == (impl.conclusion & impl.premise);
}
static void Main(string[] args)
{
Implies<int> impl= 0.Implies(2); // will be called directly
Infers<int> impl2 = 0.Infers(2); // will be converted
Console.WriteLine("Res: {0} {1}", Evaluate(impl), Evaluate(impl2));
Console.ReadLine();
}
}