Как применять сигнатуру типа - PullRequest
0 голосов
/ 22 октября 2018

В приведенном ниже коде queue_it неожиданно изменяет сигнатуру типа.Как мне решить эту проблему?

module foo = 
    type MBase() =
        member __.id = 42

    type User() = inherit MBase()
    type User2() = inherit MBase()

    let queue_it f  = fun x -> f x 
    let _find(x:int) = (Unchecked.defaultof<#MBase>)

    let find0 = fun x -> _find x    // int -> #MBase
    let findq0 = queue_it _find     // int -> MBase  ??

    let u1 : User  = find0 42
    let u2 : User2 = find0 42
    let u3 : User  = findq0 42
    let u4 : User2 = findq0 42 // error: Expected User2 but given User

1 Ответ

0 голосов
/ 22 октября 2018

Как решить, это простая часть, сделать findq0 универсальную функцию :

let findq0 x = queue_it _find x // int -> 'a

Разница с тем, что у вас было, в том, что в вашей версии

let findq0 = queue_it _find    // int -> User

findq0 является родовым значением , что является проблемой для .Net, которая обычно приводит к сообщению об ошибке, подобному этому

Ограничение значения.Значение 'findq0' было выведено, чтобы иметь универсальный тип val findq0: (int -> '_a), когда' _a:> Answer.foo.MBase Либо сделать аргументы для 'findq0' явными, либо, если вы не собираетесь использовать егочтобы быть общим, добавьте аннотацию типа.

Вы можете увидеть сообщение, если закомментируете последние 2 строки своего кода.F # пытается избежать этого сообщения, угадывая неуниверсальное значение, основанное на вашем первом использовании findq0, а именно:

    let u3 : User  = findq0 42

Эта строка говорит F #, что findq0 должно возвращать значение типа User и поэтому он определяет, что он должен иметь тип int -> User.Следующая строка противоречит этому, и вы получите сообщение об ошибке:

Ожидается, что это выражение будет иметь тип 'User2', но здесь имеет тип 'User'

...