2015-10-02 11 views
7

Consideriamo ho due differenti biblioteca tipi:funzione e il tipo di linea di estensione

type Foo = { foo : string } 
type Bar = { bar : int32 } 

Voglio realizzare funzione generica zoo che lavorerà sia per Foo o Bar istanze. E non posso modificare Foo e Bar perché fanno parte del codice della libreria.

Ecco il mio primo tentativo utilizzando le estensioni di tipo e funzione inline come spiegato here:

// Library.fs 
module Library 

type Foo = { foo : string } 
type Bar = { bar : int32 } 

// Program.fs 
type Foo with 
    static member zoo (f : Foo) = "foo" 

type Bar with 
    static member zoo (b : Bar) = "bar" 

let inline zoo (x : ^t) = 
    (^t : (static member zoo : ^t -> string) x) 

let f = zoo { foo = "1" } // error FS0001: The type 'Foo' does not support the operator 'zoo' 

Perché non inline definizione della funzione si basa su estensioni di? Come posso risolvere il mio problema senza modificare le definizioni iniziali di tipo Foo e Bar?

risposta

11

Utilizzare il metodo di sovraccarico.

Il problema con i metodi di estensione è che non vengono presi in considerazione quando solving member constraints.

Quindi è possibile utilizzare il metodo overload, come già indicato nella propria risposta oppure è possibile andare oltre e creare una funzione generica incorporata utilizzando un tipo intermedio e un metodo intermedio (in questo caso un operatore per semplicità) per eseguire trucco:

type T = T with 
    static member ($) (T, x:Foo) = "foo" 
    static member ($) (T, x:Bar) = "bar" 

let inline zoo x = T $ x 

let f = zoo { foo = "1" } 

Qui avete more details su come funziona.

Tenere presente che questa funzione verrà sottolineata, quindi ad esempio non sarà possibile richiamarla da C#, se è necessario non utilizzare una funzione, utilizzare un overload di metodo semplice e standard.

1

La cosa migliore che ho potuto ottenere finora è

type Ext = 
    static member zoo (f : Foo) = "foo" 
    static member zoo (b : Bar) = "bar" 

let f = Ext.zoo { foo = "1" } // "foo" 
let b = Ext.zoo { bar = 2 } // "bar" 

Non è la soluzione migliore e non molto generico, ma almeno funziona.

Problemi correlati