Не думаю, что это возможно, но мне очень нравится идея :-).
Если бы это было возможно, то ограничения, вероятно, были бы записаны с использованием того же синтаксиса, который можно использовать для записи ограничений интерфейса для параметров обычного (не измеряемого) типа:
let rate<[<Measure>] 'u when 'u :> IMetric> (distance:float<'u>) (time:float<time>) =
distance/time
в сообщении об ошибке ясно сказано, что ограничения могут быть указаны только для параметров обычного типа (на самом деле, я даже удивился, что единицы измерения могут реализовывать интерфейсы - это не выглядит очень полезным, поскольку они полностью стираются во время компиляции):
ошибка FS0703: ожидаемый параметр типа, а не параметр единицы измерения
Лучший обходной путь, о котором я могу подумать, - это написать простую оболочку, которая хранит значение (с некоторой единицей измерения)) и дополнительный (фантомный) тип, представляющий ограничения:
[<Struct>]
type FloatValue<[<Measure>] 'u, 'constr>(value:float<'u>) =
member x.Value = value
let cm f = FloatValue<_, IMetric>(f * 1.0<cm>)
Функция cm
принимает значение с плавающей точкой и упаковывает его в FloatValue
.Второй тип аргумента является аргументом обычного типа, поэтому он может быть предоставлен с некоторым типом, который реализует интерфейсы (или только с одним интерфейсом).Тогда функция rate
выглядит следующим образом:
let rate (distance:FloatValue<'u, #IMetric>) (time:float<time>) =
distance.Value / time
Поскольку ограничения не могут быть указаны для типа объекта, мы должны указать их для аргумента второго типа.Затем вы можете вызвать функцию, используя:
rate (cm 10.0) 5.0<time>