Отсутствует ограничение типа в F#

В следующем коде обратите внимание на ограничение типа для get_Zero:

type Wrapper<'t> = { Data : 't[] }

let compute<'t
    when 't : (static member get_Zero : unit -> 't)
    and 't : (static member (~-) : 't -> 't)
    and 't : (static member (+) : 't * 't -> 't)>
        (wrapper : Wrapper<'t>) =
    wrapper.Data
        |> Seq.mapi (fun i value -> (i, value))
        |> Seq.sumBy (fun (i, value) ->
            if i % 2 = 0 then value
            else -value)

Несмотря на то, что у меня уже есть явное ограничение типа, я все еще получаю следующую ошибку компилятора при вызове Seq.sumBy:

В параметре типа отсутствует ограничение «когда ^t : (статический член get_Zero : -> ^t)»

Кто-нибудь знает, что здесь происходит? Спасибо.


person brianberns    schedule 16.09.2014    source источник
comment
Помимо того, что на этот вопрос уже есть очень правильный ответ, я хотел бы подчеркнуть, что когда вы используете SRTP (параметры статически разрешенного типа), как вы делаете с этими ограничениями static member и т. д., тогда функция должна быть inline и вместо использования 'T, вместо этого используйте ^t (имеется в виду: ^, а не '). См. также: docs.microsoft .com/en-us/dotnet/fsharp/language-reference/   -  person Abel    schedule 01.11.2019


Ответы (1)


Попытка сделать явными ограничения нижестоящего статического члена может привести к разочарованию и, к счастью, редко бывает необходимой. Просто отметьте функцию inline и позвольте им быть выведенными.

let inline compute (wrapper : Wrapper<_>) =
    wrapper.Data
    |> Seq.mapi (fun i value -> (i, value))
    |> Seq.sumBy (fun (i, value) ->
        if i % 2 = 0 then value
        else -value)

Правильная подпись:

let inline compute<'t
            when 't : (static member Zero : 't)
            and 't : (static member (~-) : 't -> 't)
            and 't : (static member (+) : 't * 't -> 't)>

(Вы заметите, что подпись в сообщении об ошибке даже не является допустимым синтаксисом: when ^t : (static member get_Zero : -> ^t). Это часть того, что я имею в виду под разочарованием.)

person Daniel    schedule 16.09.2014
comment
Почему встроенная версия работает? Компилятор выводит ограничения. sumBy является встроенным, и его ограничения распространяются на потребляющую функцию, также помечая его как встроенное. - person Daniel; 16.09.2014
comment
Это работает, но на самом деле не отвечает на вопрос. Он также не работает с расширениями типов, которые вызывают функцию вычисления: type Wrapper<'t> with member inline wrapper.Compute = wrapper |> compute - person brianberns; 16.09.2014
comment
@brianberns: я обновил свой ответ рабочей подписью. Расширение типа не работает, потому что оно использует универсальный аргумент, определенный для типа, а ограничения на общие аргументы уровня типа должны быть явными. - person Daniel; 16.09.2014