Question

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?
Was it helpful?

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<_>)

OTHER TIPS

I don't think you need to specify types for variables yourself, let F# do type inference. So the below declaration is enough:

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

If you don't want to specify record field names (which I think is nice to make your program clear), you can change your record to a class (like in @Tarmil's answer) or a disjoint union. Personally, I like disjoint unions more because I still can use them in pattern matching easily:

type Vector3<[<Measure>] 'a> = Vector3 of float<'a> * float<'a> * float<'a>

let my_var1 = Vector3(1.0, 1.0, 1.0) // Vector3<1>
let my_var2 = Vector3(1.0<m>, 1.0<_>, 1.0<_>) // Vector3<m>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top