Problema SommarioCome convertire implicitamente in tipi di super comuni in F # pattern matches?
Nel momento in cui utilizza f # devo costringere in modo esplicito un valore per il tipo di genitore di questo tipo al fine di ottenere di pattern corrispondenti espressioni di digitare controlla correttamente. Preferirei un modo più ordinato di fare.
Esempio
Supponiamo che io sono un po 'di classe gerarchia:
type Foo() =
abstract member Value : unit -> string
type A (i:int) =
inherit Foo()
override this.Value() = i.ToString()
type B (s:string) =
inherit Foo()
override this.Value() = s
Idealmente, e in alcuni linguaggi di programmazione in Normalmente, vorrei scrivere l'equivalente di quanto segue:
let bar (i:int) : Foo =
match i with
| 1 -> B "one"
| _ -> A i
Tuttavia non riesce a digitare correttamente il check, dandomi l'errore, "Questa espressione avrebbe dovuto avere tipo Foo ma lei e ha tipo B ". Non capisco perché il compilatore non abbia abbastanza informazioni per dedurre un super tipo comune per l'espressione della corrispondenza e quindi verificare che il super tipo comune sia 'Foo'.
Allo stato attuale sono costretto a fornire una coercizione esplicita per tutti i casi nella partita modello:
let bar2 (i:int) : Foo =
match i with
| 1 -> (B "one") :> Foo
| _ -> (A i) :> Foo
vorrei evitare questo.
Ulteriori avvertenze
- L'intuizione suggerisce che questo è il risultato di un problema più generale. Avrei pensato però che qualcosa di così comune come la corrispondenza dei pattern, o se le istruzioni che esibiscono la stessa proprietà, avrebbero una regola di controllo del tipo per tenere conto dei super-tipi comuni.
- Prima che qualcuno mi suggerisca - Apprezzo che se A o B fossero espressioni oggetto funzionerebbe, ma il mio vero esempio è la creazione di istanze di classi C# in cui sono classi normali.
- C'è un modo per me di dichiarare le funzioni per convertire implicitamente i tipi, come ad esempio scala ha, quindi posso applicare le conversioni automatiche per il modulo in cui sto facendo questa generazione?
Grazie per qualsiasi aiuto in merito.
Il motivo per cui il correttore di tipi non esegue alcuna shenanigans con tipi derivati è che in primo luogo renderebbe più complicata la fase di controllo del tipo e in secondo luogo consentirebbe di introdurre bug sottili. Ad esempio, considerare quanto segue: corrispondenza i con | 1 -> B ("uno") | 2 -> "stuff" Bene, sia System.String che B condividono il tipo di base comune System.Object, quindi il risultato di tale espressione di corrispondenza è di tipo obj. Il 99,9% non è quello che volevi. –
È vero, anche se nell'istanza specifica che l'OP sta chiedendo, ha già dichiarato la funzione return type come ': Foo', quindi penso che forse non sarebbe del tutto irragionevole per l'inferitore utilizzarlo come un più grande- legato o qualcosa. Non ho pensato a tutte le implicazioni di ciò, però. – Brian
Penso che 'x:> _' sia migliore di' upcast x', ma forse sono solo io. I rami della partita non si allineano, però. – kvb