2012-03-16 5 views
5

Piccola parte di un codice per evidenziare il problema:accattivarsi dei 'tipi flessibili' in F #

open System.IO 

let do_smth i (stm : #System.IO.Stream) = // val do_smth : 'a -> #Stream -> unit 
    (*....*) 
    () 

type SomeOps = SomeOps with 
    static member op (i : int) = do_smth i 

let test_currying i = do_smth i   // val test_currying : 'a -> (Stream -> unit) 
              // NB: Stream, not #Stream 
let main() = 
    use stm = new System.IO.MemoryStream() 
    test_currying 42 stm // OK, upcasted to Stream somehow 
    SomeOps.op 42 stm  // compiler error! 

qualcuno può spiegare, perché è il comportamento del compilatore in modo diverso negli ultimi due righe? E perché abbiamo perso le informazioni (sulla flessibile #Stream) nella funzione test_currying?

risposta

3

Questo mi sembra un insetto. Il compilatore gestisce funzioni diverse costruite usando let e funzioni scritte come static member.

In particolare, penso che non inserisca tipi flessibili per gli argomenti dei membri che non sono dichiarati esplicitamente nella dichiarazione membro (ovvero argomenti che sono il risultato di un'applicazione di funzione parziale o creati utilizzando il costrutto fun) .

L'esempio più semplice che illustra il comportamento non usa tipo flessibile e si presenta così:

type A = 
    static member op = fun (s:obj) ->() 
module B = 
    let op = fun (s:obj) ->() 

A.op "A" // Error 
B.op "A" // Ok 

Secondo la specifica (? Sezione 14.4.2, pubblicato da Brian in un eliminato() risposta), un flessibile il tipo che consente di utilizzare supertipi deve essere inserito indipendentemente dal fatto che la funzione invocata sia membro o un valore let-bound.

+0

Quindi, è un comportamento corretto, giusto? – qehgt

+0

Non penso che ciò che fa il compilatore al momento sia un comportamento corretto. Non vedo una ragione per cui i due casi dovrebbero comportarsi diversamente. Ecco perché ho detto che mi sembra un insetto. –

+0

Ok, capisco. Grazie. – qehgt