Dropping IConvertible
Beginnen wir mit dem 'easy Teil' starten: IConvertible
fallen. Der Grund, warum Sie es brauchen, ist, dass Sie möchten, dass dieser Code auf allen Arten funktioniert, was bedeutet, dass Sie nicht immer beeinflussen können, dass er ein bestimmtes Mitglied hat (Implies
). Was Sie möchten, dass tun, was sie in C++ rufen: Template-Spezialisierung, aber leider nicht verfügbar ist in C# (noch?):
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
Der einfachste Weg, dies durch die Verwendung Multimethoden zu lösen ist.
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);
}
}
Und wenn Sie eine ‚dritte‘ Methode haben, können Sie einfach nennen es
Ich habe in der ein paar Minuten gesucht: Sie können das ‚dynamische‘ Schlüsselwort für diesen Einsatz seltsam rekursive Definition und es ergibt keinen Sinn für mich ... Wenn Sie eine dritte Hilfsmethode sowieso haben, warum nicht einfach direkt anrufen? :-)
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);
}
Die nicht (nicht (T)) Problem
Während die oben nicht viel Sinn für mich habe, finde ich es durchaus sinnvoll, die Art System und die Sprache zu verwenden um dir ein bisschen zu helfen. Nun, sicher können Sie das tun und das ist, wie ich das tun würde ... :-)
Lassen Sie uns einen einführen ‚Nicht‘ Klasse mit einem generic:
public class Not<T>
{
public Not(T val)
{
this.not = val;
}
internal T not;
}
Wenn wir eine Nicht> Situation haben hier wollen wir geben - sonst wollen wir direkt verwenden.Nun, wir können mit einigen Erweiterungen, die ganz einfach tun:
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;
}
es zu testen, können Sie eine ähnliche Sache tun:
var val = new Not<Not<int>>(new Not<int>(2));
var result = val.Optimize();
Dies funktioniert, weil die Überladungsauflösung den richtigen Optimize Anruf anzunehmen wird, was sicherstellt, dass Sie das Nicht >>>> in den T-Wert optimieren und so weiter.
Es funktioniert auch, weil wir das 'Not' in einer Wrapper-Klasse umhüllen und dann das Typsystem zu unserem Vorteil verwenden.
Gehen wir zurück zum ursprünglichen Problem
Statt direkt die Bewertung ‚Impliziert‘ und ‚folgert‘, warum nicht ein temporäres Objekt verwenden, um Ihre bösen Arbeit zu tun. Sie können das Überladen von Operatoren (implizite Konvertierung, um genau zu sein) verwenden, um anzugeben, wie sich Imples und Infers verhalten. Der einzige Haken ist, dass es mit Erweiterungsmethoden Grenzen hat.
C# -Operatorüberladung wählt dann die am besten passende Methode aus. Im ersten Fall ist dies die exakte Übereinstimmung, im zweiten Fall wird die Methode implizit konvertiert und anschließend wird Evaluate aufgerufen. Mit anderen Worten, es wird keinen Überlauf stacken, nur weil es seine Bewertung faul macht. Bereit für den Code? :-)
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();
}
}
[* Paradox *] (http://www.veterangamers.co.uk/blog/wp-content/uploads/2011/04/paradox.jpg) ... –
Es ist bei diesen Punkt würde ich wahrscheinlich zu Prolog wechseln. – spender
@spender: Es ist lange her, ich habe einmal in Prolog geschrieben. Vielleicht eine Antwort von Prolog, um das Problem zu lösen? –