2010-05-13 17 views
8

Gibt es eine Möglichkeit, die Typdefinitionen hier zu verallgemeinern? Idealerweise würde ich gerne in der Lage sein, den Typ von 'testInput' zu ändern und den Test zum Kompilierungszeitpunkt korrekt abzuleiten.C# Allgemeiner Methodentyp Argumentschlussfolgerung

public static void Run() 
{ 
    var testInput = 3; 
    var test = ((Func<int, int>) Identity).Compose<int,int,int>(n => n)(testInput); 
    Console.WriteLine(test); 
} 

public static Func<T, V> Compose<T, U, V>(this Func<U, V> f, Func<T, U> g) 
{ 
    return x => f(g(x)); 
} 

public static T Identity<T> (this T value) 
{ 
    return value; 
} 

Update: ich die Art der Funktion in Compose gab angeben kann, aber dies gibt noch den Typen in der Zeile.

public static void Run() 
{ 
    var testInput = 3; 
    var identity = (Func<int, int>) Identity; 
    var test = identity.Compose((int n) => n)(testInput); 
    Console.WriteLine(test); 
} 

Ein wenig Kontext; Ich arbeite durch Wes Färber The Marvel of Monads

+0

Können Sie genauere Informationen über das, was Sie erreichen wollen? Derzeit ist Ihre Compose-Funktion zu eingeschränkt, um eine Typrückschluss von T von einem Lambda zu ermöglichen. Es kann einfach nicht genug Informationen von der Verwendung erhalten. – jeffora

+0

aktualisierte die Frage. – CaptainCasey

Antwort

3

Gut zu sehen, wie ich in einer Rolle für das Austeilen von Text heute Abend bin, werde ich meinen eigenen Stab darin haben. Ich sollte beachten, dass ich kein Experte für den C# -Compiler bin, ich habe die Spezifikation (keine von ihnen ... für irgendetwas) gelesen, und obwohl dieser Artikel, den Sie verlinkt haben, wirklich interessant war, würde ich lügen, wenn ich es sagen würde war eine Art von Experte auf dem entweder (oder auch alles zu 100% verstanden).

Caveats beiseite lässt, ist mein nehmen auf Ihre Frage so:

Gibt es eine Möglichkeit, die ich hier die Typdefinitionen verallgemeinern?

Ich denke, die kurze Antwort ist nein. Mit den bereitgestellten Informationen gibt es einfach nicht genug Informationen für den Typinferenzteil des C# -Compilers, um genug Informationen aus der Verwendung der verschiedenen Variablen abzuleiten.

Wie die anderen Antworten hier zeigen, kann es vereinfacht werden. Sie können @ Lees IdentityFunc verwenden, um Typrückschluss mit var identity zuzulassen. Aber auch mit diesem Zusatz ist es immer noch nicht möglich, mit Ihrem Beispielcode auf alle Typvariablen von Compose zu schließen.

Stellen Sie sich folgende Situation:

public static Func<T, V> Compose<T, U, V>(this Func<U, V> f, Func<T, U> g) 
{ 
    return x => f(g(x)); 
} 

public static T Identity<T> (this T value) 
{ 
    return value; 
} 

public static Func<T, T> IdentityFunc<T>(this T value) 
{ 
    return (Func<T, T>)Identity; 
} 

und

public static void Run() 
{ 
    var a = 3; // a is int 
    var i = a.IdentityFunc(); // i is Func<int, int>; 
    var test = i.Compose(n => n)(a) // test is expected to be int 
} 

Zunächst dies erscheinen mag, als ob test leicht zu int rein zufällig. Der Rückgabetyp i.Compose kann jedoch erst nachträglich aus seiner Verwendung abgeleitet werden. Der C# -Compiler wird dies offensichtlich nicht erlauben.

public static void Run() 
{ 
    var a = 3; // a is int 
    var i = a.IdentityFunc(); // i is Func<int, int>; 
    var c = i.Compose(n => n) // c is Func<T, int> - T cannot be resolved without knowledge of n 
    var test = c(a); // ideally have type inference infer c (Func<T, int>) as Func<int, int> 
} 

In diesem Beispiel bei Verwendung von c mit a würde der Compiler nachträglich den Rückgabetyp des Anrufs i.Compose<T, U, V>(n => n) schließen muß Func<int, int> sein. Dies ist im C# -Compiler offensichtlich nicht möglich. Nehmen Sie den Anruf c(a) und der Compiler würde keine Kenntnis von der Verwendung von c, die jede Möglichkeit der Ableitung von T (nicht, dass es sowieso kann) zu entfernen. Es ist möglich, dass ein fortgeschritteneres Typ-Inferenzsystem diese Art von Schlussfolgerung basierend auf der Verwendung einer generischen Rückkehr durchführen könnte (möglicherweise F # - ein anderes Thema, zu dem ich kein Experte bin).

Da Wes Dyer keine spezifische Verwendung dieses bestimmten Beispiels bietet, ist es unbekannt, ob es eine andere Magie gibt, die er verwendet, um den Grad der Typinferenz zu berücksichtigen, die Sie erreichen möchten.

Mehr qualifizierte Menschen wie Eric Lippert würden in der Lage sein, Sie mit einem viel höheren Detaillierungsgrad (und technische Genauigkeit/Schärfe) zu bieten. Ich habe eine große Antwort gelesen, die er hier auf eine Frage über Typinferenz geschrieben hat, aber ich kann sie nicht finden. Sein blog hat viele gute Informationen. Sie könnten versuchen, ihn zu kontaktieren, wenn Sie interessiert sind. Auch seine Antwort auf diese Frage hier diskutiert Monaden (und verlinkt schließlich zurück zu Wes Dyer's Artikel) kaufen Sie könnten daran interessiert sein, es zu lesen: Monad in plain English? (For the OOP programmer with no FP background)

+2

Eigentlich habe ich Ihrer Antwort nicht viel hinzuzufügen. Wie Sie richtig bemerken, haben wir nicht genug Informationen, um T von der Aufrufseite von Compose abzuleiten, ohne den Typ des Lambda-Parameters. Und wie Sie bemerken, wenn wir die Analyse bis zur Verwendung des zusammengesetzten Ergebnisses zurückstellen könnten, könnten wir mehr Fortschritte machen, aber das tun wir nicht. –

+0

Vielen Dank für eine ausgezeichnete Antwort auf die Frage. Diese Antwort hat keine positiven Bewertungen. – CaptainCasey

2

Sie könnten eine Erweiterungsmethode schreiben die Identitätsfunktion für einen Typ zurück:

public static Func<T, T> IdentityFunc<T>(this T value) 
{ 
    return (Func<T, T>)Identity; 
} 

(oder nur return v => value;)

Ihr Test wird dann

var testInput = 3; 
var identity = testInput.IdentityFunc(); 
test = identity.Compose((int n) => n)(testInput); 
1

Am nächsten komme ich, um den Parameter für das n => n Lambda:

explizit einzugeben
var test = ((Func<int, int>)Identity).Compose((int n) => n)(testInput); 
1

Ich glaube nicht, dass Sie Ihr Ideal erreichen können; C# Typ Inferenz funktioniert nicht so.

Sie könnten F # genießen.

Verwandte Themen