2012-08-15 3 views
8

Diese aktiven Muster mit F 2.0 # kompilieren:Aktive Muster in F # gebrochen 3.0

let (|Value|_|) value = // 'a -> 'T option 
    match box value with 
    | :? 'T as x -> Some x 
    | _ -> None 

aber in F # 3.0, gibt den Fehler:

Active pattern '|Value|_|' has a result type containing type variables that are not determined by the input. The common cause is a [sic] when a result case is not mentioned, e.g. 'let (|A|B|) (x:int) = A x'. This can be fixed with a type constraint, e.g. 'let (|A|B|) (x:int) : Choice = A x'

Ich habe versucht:

let (|Value|_|) value : 'T option = ... 

und:

let (|Value|_|) (value: 'U) = ... 

Wie kann es behoben werden?

Umgebungen: Visual Studio 2012 (RTM) und FSI v11.0.50727.1

EDIT: Hier ist ein einfacher Repro:

let (|X|) x = unbox x 
+0

Funktioniert gut für mich, Visual Studio 2012 RC aktualisiert, 'Microsoft (R) F # 3.0 Interaktive Build 11.0.50522.1'. Wenn ich den Fehler sehe, denke ich immer noch, dass es funktionieren sollte (so wie es ist). Das Beispiel im Fehler ('let (| A | B |) (x: int) = A x') zeigt tatsächlich den von Ihnen geposteten Fehler. –

+1

'F # 2.0 interaktive Build 4.0.40219.1' gibt genau die gleichen Ergebnisse. –

+0

Sorry, ich hätte etwas genauer in Bezug auf die Umgebung sein sollen. Ich habe die Frage aktualisiert. – Daniel

Antwort

4

Es gab einen Fehler im F # 2.0-Compiler, bei dem der Compiler eine falsche Analyse und eine fehlerhafte Codegenerierung für bestimmte aktive Muster mit freien Typvariablen im Ergebnis durchgeführt hat. eine einfache Repro ist

let (|Check|) (a : int) = a, None 
//let (|Check|) (a : int) = a, (None : int option) 

let check a = 
    match a with 
    | Check (10, None) -> System.Console.WriteLine "10" 
    | Check (20, None) -> System.Console.WriteLine "20" 

check 10 
check 20 

, die zur Compile-Zeit eine seltsame Warnung erzeugt und scheinbar falschen Code kompiliert in. Ich vermute, dass unser Versuch, diesen Fehler zu beheben (und einige verrückte Fälle einzuschränken) in F # 3.0 auch einige Rechtskodes als Kollateralschaden des Updates durchbrochen hat.

Ich werde einen weiteren Fehler einreichen, aber für F # 3.0 klingt es so, als müssten Sie eine der in anderen Antworten erwähnten Problemumgehungen verwenden.

+0

Wurde dies für F # 3.1 behoben? –

3

ich die neue Version noch nicht installiert, aber ich stimme dieser sieht ein bisschen fischig aus. Ich denke, dass es einen guten Grund für diese Einschränkung geben kann, aber Ihr Beispiel in der anderen Frage scheint ziemlich zwingend.

Als Abhilfe können, denke ich, dass ein Zeuge Parameter hinzugefügt (das nicht verwendet wird, aber Hinweise, was der Typ des Ergebnisses sein wird) funktionieren könnte:

let (|Value|_|) (witness:unit -> 'T) value : 'T option = 
    match box value with 
    | :? 'T as x -> Some x 
    | _ -> None 

Natürlich ist dies das macht benutze ein bisschen hässlicher, weil du ein Argument finden musst. In der oben verwendete ich Zeuge vom Typ unit -> 'T, in der Hoffnung, dass die folgenden kompilieren könnten:

let witness() : 'T = failwith "!" 

match box 1 with 
| Value witness 1 -> printfn "one" 

Wenn das nicht funktioniert, dann können Sie wahrscheinlich Zeuge Parameter vom Typ versuchen Sie es mit 'T (aber dann haben Sie ein schaffen tatsächliche Funktion, anstatt nur eine generische Funktion).

+0

Danke für die Umgehung: Ich kann mir keinen "guten Grund" vorstellen, etwas zu brechen, das in einer früheren Version funktioniert (und nützlich ist). :-) – Daniel

+0

Die Problemumgehung in [meine Antwort] (http://stackoverflow.com/a/11990910/162396) (von Kvb inspiriert) zu einer Folgefrage, benötigt nicht den Parameter 'Zeuge' und behält die ursprüngliche Verwendung bei. – Daniel

0

Sehen Sie meine answer zu Ihrer anderen question für einige Gedanken darüber, wie man das Problem umgehen und einen Grund, dass solche aktiven Muster möglicherweise unerwünscht sind. Ich bin mir nicht sicher, ob die Bruchänderung beabsichtigt war.

2

aus Gründen der Vollständigkeit, noch eine Abhilfe:

type Box<'R> = Box of obj 

let (|Value|_|) ((Box x) : Box<'R>) : 'R option = 
    match x with 
    | :? 'R as x -> Some x 
    | _ -> None 

let check t = 
    match Box t with 
    | Value 1 -> printfn "one" 
    | Value 2 -> printfn "two" 

check 1 // one 
check 2 // two 

aber noch wird es von dem Problem von @kvb in another thread erwähnt leiden. Persönlich bevorzuge ich @ kvb-Version mit parametrisierten aktiven Muster.

Verwandte Themen