2010-12-19 16 views
16

Czy ktoś wie, dlaczego to się nie kompiluje?Błąd dziedziczenia interfejsu F # z powodu jednostki

type MyInterface<'input, 'output> = 
    abstract member MyFun: 'input -> 'output 

type MyClass() = 
    interface MyInterface<string, unit> with 
     member this.MyFun(input: string) =() 
    //fails with error FS0017: The member 'MyFun : string -> unit' does not have the correct type to override the corresponding abstract method. 
type MyUnit = MyUnit 
type MyClass2() = 
    //success 
    interface MyInterface<string, MyUnit> with 
     member this.MyFun(input: string) = MyUnit 

Odpowiedz

15

To wygląda bolesnego rogu literami w języku F #, ale nie jestem pewien, czy to kwalifikuje się jako ograniczenie ubocznych projektowania lub błąd w kompilator. Jeśli jest to z powodu ograniczenia projektu, komunikat o błędzie powinien to powiedzieć (ponieważ obecnie nie ma to większego sensu).

W każdym razie problemem jest to, że kompilator F # nie generuje kodu, który faktycznie zawiera typ unit w IL. Zastępuje go void (gdy jest używany jako typ zwracany) lub z pustą listą argumentów (gdy jest używana jako metoda lub argument funkcji).

Oznacza to, że w typie MyClass, kompilator zdecyduje się skompilować człon MyFun jako metody, które odbywają string i powraca void (ale nie można używać void jako ogólny typ argumentu, więc to po prostu nie działa). Zasadniczo kompilator może używać rzeczywistego typu unit w tym przypadku (ponieważ jest to jedyny sposób, aby to działało), ale prawdopodobnie spowoduje to inne niespójności w innym miejscu.

Twoja sztuczka polegająca na tworzeniu MyUnit jest, moim zdaniem, doskonałym sposobem na rozwiązanie problemu. Nawet podstawowa biblioteka F # używa czegoś takiego jak MyUnit w niektórych miejscach implementacji (w asynchronicznych przepływach pracy), aby poradzić sobie z pewnymi ograniczeniami związanymi z unit (i sposobem, w jaki jest kompilowany).

+0

Dzięki Tomas. Nie widziałem tego problemu gdzie indziej (np. W normalnych funkcjach z let;) –

+0

@Stefan: Jeśli użyjesz argumentu 'unit' jako argumentu (do funkcji lub typu), to ogólnie jest w porządku. Ten błąd/ograniczenie prawdopodobnie pojawia się tylko podczas implementowania abstrakcyjnych elementów (co jest nieco trudnym obszarem dla kompilatora F #, ponieważ dziedziczenie jest zaskakująco skomplikowane w .NET). –

+1

Co ciekawe, będzie działać w języku C# i będę mógł korzystać z funkcji w F #. Prawdopodobnie powinien zostać zgłoszony jako błąd. –

Powiązane problemy