Некоторые способы использования не компилируются, когда одна сторона оператора имеет известный тип, а другой - нет. Одним из примеров является с единицами измерения:Почему автоматическое обобщение иногда выдает чрезмерно конкретные типы?
let inline multiplyWithFive x = 5. * x
type [<Measure>] myUnit
let test = multiplyWithFive 3.<myUnit> // Compiler error
5. * 3.<myUnit>
явно допустимое выражение, так что это удивительно, особенно если учесть, что inline
функции обобщать максимально в других случаях:
let inline multiply a b = a * b
let test = multiply 5. 3.<myUnit> // Valid
Это не ограничено к единицам измерения. Скажем, я делаю тип, который поддерживает асимметричное умножение с помощью float. Это несовместимо с функцией multiplyWithFive
, которая произвольно выводит его параметр как float
:
type BoxFloat =
{ Value : float }
static member inline (*) (lhs : float, rhs : BoxFloat) =
{ Value = lhs * rhs.Value }
let boxThree = { Value = 3. }
let test2 = multiplyWithFive boxThree // Compiler error
Опять 5. * boxThree
является допустимым выражением. Но автоматическое обобщение, похоже, не признает этого.
Я могу «исправить» первый случай с аннотациями типа единицы измерения, но это ограничивает базовый тип без видимых причин. Если мне действительно нужна более общая функция, я не знаю, как остановить компилятор от ограничений. Если я явно укажу общий параметр, он просто отказывается сохранить его общий:
// Warning: This construct causes code to be less generic than indicated...
let inline multiplyWithFive (x : 'T) = 5. * x
Что я могу сделать с этим? Есть ли способ сказать, что мне нужна более общая версия?
Oooh! Это особый случай для некоторых примитивных типов и операторов! Поведение отличается, если я использую собственный тип вместо float! Я думаю, что первая часть этого ответа является частным случаем второй части. Как видно из «let inline multiply a b = a * b», компилятор не обязательно умаляет обобщение по единицам измерения. И при задании 'type M <[] 'u>() = class end',' let inline multiplyWithM x = M () * x' выводится максимально общим! –
Vandroiy