9

I just wondered how it is possible to write a user-defined square root function (sqrt) in a way that it interacts properly with F#'s unit system.

What it should be like:

let sqrt (x : float<'u ^ 2>) =
    let x' = x / 1.0<'u ^ 2> // Delete unit
    (x ** 0.5) * 1.0<'u>     // Reassign unit

But this is disallowed due to nonzero constants not being allowed to have generic units.

Is there a way to write this function? With the builtin sqrt it works fine, so what magic does it perform?

kvb
  • 54,864
  • 2
  • 91
  • 133
Dario
  • 48,658
  • 8
  • 97
  • 130
  • 1
    Related question: (also answered by @kvb) http://stackoverflow.com/questions/1398611/f-ununit-reunit-inside-a-function – Benjol Oct 02 '09 at 11:42

2 Answers2

6

Allowing nonzero generic constants would make it very easy to break the safety of the type system for units (see Andrew Kennedy's papers). I believe that the answer to your last question is that sqrt is indeed magic in some sense in that it shouldn't be possible to define a parametric function with that type signature through normal means. However, it is possible to do what you want (at least in the current version of F#) by taking advantage of boxing and casting:

let sqrt (x : float<'u^2>) =
  let x' = (float x) ** 0.5 (* delete unit and calculate sqrt *)
  ((box x') :?> float<'u>)
kvb
  • 54,864
  • 2
  • 91
  • 133
6

@kvb is right, more generally:

If you have a non-unit aware algorithm (e.g. say you write 'cube root'), and you want to put units on it, you can wrap the algorithm in a function with the right type signature and use e.g. "float" to 'cast away' the units as they come in and the box-and-downcast approach to 'add back' the appropriate units on the way out.

In the RTM release (after Beta2), F# will have primitive library functions for the 'add back units', since the box-and-downcast approach is a currently bit of a hack to overcome the lack of these primitives in the language/library.

Brian
  • 117,631
  • 17
  • 236
  • 300
  • Thanks - Could you name these new library functions (Link)? – Dario Oct 02 '09 at 16:23
  • 3
    They will probably be named e.g. "val inline FloatWithMeasure : float -> float<'u>" in the LanguagePrimitives module. – Brian Oct 02 '09 at 22:55