Подтвердить что ты не робот

F # наследование наследования интерфейса из-за единицы

Кто-нибудь знает, почему это не удается скомпилировать?

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
4b9b3361

Ответ 1

Это выглядит как неприятный угловой случай на языке F #, но я не уверен, что он квалифицируется как ограничение по дизайну или ошибка в компиляторе. Если это ограничение по дизайну, тогда сообщение об ошибке должно сказать это (потому что в настоящее время это не имеет большого смысла).

В любом случае проблема заключается в том, что компилятор F # не генерирует код, который фактически содержит тип unit в IL. Он заменяет его void (при использовании в качестве возвращаемого типа) или с пустым списком аргументов (при использовании в качестве аргумента метода или функции).

Это означает, что в типе MyClass компилятор решает скомпилировать элемент MyFun как метод, который принимает string и возвращает void (но вы не можете использовать void как аргумент общего типа, так что это просто не работает). В принципе, компилятор может использовать фактический тип unit в этом случае (потому что это единственный способ заставить его работать), но это, вероятно, создало бы другие несоответствия в других местах.

Ваш трюк с созданием MyUnit - это, я думаю, совершенно прекрасный способ решить проблему. Даже основная библиотека F # использует что-то вроде MyUnit в некоторых местах реализации (в асинхронных рабочих процессах) для решения некоторых ограничений unit (и способа ее компиляции).