Search code examples
f#recordmeasure

Simplify record assignment in F#


let's say I defined a module to handle vectors with measure unit in F#:

module Vec

    [<Measure>]
    type m

    type Vector3<[<Measure>] 'a> =
        {
        X : float<'a>
        Y : float<'a>
        Z : float<'a>
        }

now I would like to create a variable with let holding a Vector3. I can do something like :

let my_var : Vector3<m> = {X = 1.0<m> ; Y = 1.0<m> ; Z = 1.0<m>};

I have to do a lot of assignments like the one above, so I was wondering, is there any way to simplify the previous syntax? Something like:

let my_var : Vector3<m> = { 1.0,1.0,1.0} //this don't compile
let my_var : Vector3<m> = {1.0<m> ; 1.0<m> ; 1.0<m>} //this don't compile either

I would like:

  1. avoid the measure unit specification (1.0<m>), is this possible? isn't m implicetly derivable from the declaration my_var : Vector3<m> ?
  2. avoid the use of record field name (like in the second example). Isn't the field name of the record derivable by the compiler itself based on the order?

Solution

  • avoid the measure unit specification (1.0), is this possible? isn't m implicetly derivable from the declaration my_var : Vector3 ?

    Actually, 1.0 is equivalent to 1.0<1>, so you cannot use it in a context where a measure other than 1 (dimensionless) is expected.

    You can, however, use the inference by using 1.0<_>.

    avoid the use of record field name (like in the second example). Isn't the field name of the record derivable by the compiler itself based on the order?

    The closest thing I can think of would be the following:

    type Vector3<[<Measure>] 'a> =
        val X : float<'a>
        val Y : float<'a>
        val Z : float<'a>
        new(x, y, z) = { X = x; Y = y; Z = z }
    

    which can then be used as such:

    let my_var = Vector3<m>(1.0<_>, 1.0<_>, 1.0<_>)