2012-03-16 16 views
5

niewielką część kodu, aby podkreślić problem:Zmiękczanie z „elastycznych typów” w 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! 

Może ktoś wyjaśnić, dlaczego jest zachowanie kompilator tak różne w ostatnich dwóch wierszach? I dlaczego straciliśmy informacje (o elastyczności #Stream) w funkcji test_currying?

Odpowiedz

3

To wygląda jak błąd. Kompilator obsługuje różne funkcje utworzone za pomocą let i funkcje zapisane jako static member.

W szczególności, myślę, że nie wkładać elastycznych typów argumentów członkowskich, które nie są jawnie zadeklarowane w deklaracji członkowskim (to argumenty, które są albo wynikiem częściowego zastosowania funkcji lub są tworzone przy użyciu fun konstruktu) .

Najprostszym przykładem, który demonstruje zachowanie nie wykorzystuje elastyczną typ i wygląda następująco:

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

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

Zgodnie ze specyfikacją (? Sekcji 14.4.2, napisanych przez Briana w usuniętej() Odpowiedź), elastyczny typ, który pozwala na użycie supertypów, niezależnie od tego, czy wywoływana funkcja jest elementem, czy wartością dopuszczalną.

+0

To jest prawidłowe zachowanie, prawda? – qehgt

+0

Nie sądzę, że to, co obecnie robi kompilator, jest poprawnym zachowaniem. Nie widzę powodu, dla którego te dwie sprawy powinny zachowywać się inaczej. Dlatego powiedziałem, że wygląda mi na błąd. –

+0

Ok, widzę. Dzięki. – qehgt

Powiązane problemy