Анкур прав: вы не можете этого сделать (не прибегая к взломам, которые могут сломать юнитов).
Возможно, более ясное описание проблемы заключается в том, что тип функции pow
будет зависеть от значения аргумента, а F # не позволяет вам это сделать.Вы могли бы представить, что это сработало бы, если бы в качестве второго аргумента использовались только литералы, но было бы сложно, если бы вы использовали выражения:
pow a 3 // Assuming a = 1.0<cm>, the return type is float<cm ^ 3>
pow a n // Assuming a = 1.0<cm>, the return type is float<cm ^ n>
Во втором случае значение n
должно появиться втип!
Вы можете использовать некоторые неприятные уловки (вдохновленные этой статьей на Haskell ), но это становится немного сумасшедшим.Вместо использования числовых литералов вы должны использовать что-то вроде S(S(S(N)))
для представления числа 3
.Таким образом, вы можете привести номер в тип.Вы, вероятно, не хотите этого делать, но вот пример:
[<Measure>] type cm
// Represents a number with units of measure powered to the
// number's value (e.g "(S (S O))" has type Num<cm, cm^3>)
type Num<[<Measure>] 'M, [<Measure>] 'N> =
| O_ of int * float<'N>
| S_ of int * Num<'M, 'N / 'M>
// Constructors that hide that simplify the creation
let O : Num<'M, 'M> = O_ (1, 0.0<_>)
let S n = match n with O_(i, _) | S_(i, _) -> S_(i + 1, n)
// Type-safe power function with units of measure
let pow (x:float<'M>) ((O_(i, _) | S_(i, _)):Num<'M, 'M 'N>) : float<'M 'N> =
// Unsafe hacky implementation, which is hidden
// from the user (for simplicity)
unbox ((float x) ** float i)
let res = pow 2.0<cm> (S (S O))
РЕДАКТИРОВАТЬ: Я отправил исходный код в фрагменты F #, чтобы вы могли видеть предполагаемые типы: http://fssnip.net/4H