Упростить назначение записи в F # - PullRequest
2 голосов
/ 23 ноября 2011

допустим, я определил модуль для обработки векторов с единицей измерения в F #:

module Vec

    [<Measure>]
    type m

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

Теперь я хотел бы создать переменную с let, содержащую Vector3.Я могу сделать что-то вроде:

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

Мне нужно выполнить много заданий, подобных приведенному выше, поэтому мне было интересно, есть ли способ упростить предыдущий синтаксис?Что-то вроде:

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

Я хотел бы:

  1. избегать спецификации единицы измерения (1.0<m>), возможно ли это?не является ли m косвенно выводимым из объявления my_var : Vector3<m>?
  2. избегать использования имени поля записи (как во втором примере).Разве имя поля записи, выводимой самим компилятором, не зависит от порядка?

Ответы [ 2 ]

5 голосов
/ 23 ноября 2011

Не думаю, что вам нужно указывать типы для переменных самостоятельно, пусть F # делает вывод типов.Так что нижеприведенного объявления достаточно:

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

Если вы не хотите указывать имена полей записей (что, я думаю, хорошо, чтобы ваша программа была понятной), вы можете изменить свою запись на класс (напримерв ответе @ Тармила) или непересекающийся союз.Лично мне больше нравятся непересекающиеся союзы, потому что я все еще могу легко использовать их в сопоставлении с образцом:

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>
4 голосов
/ 23 ноября 2011

избегать спецификации единиц измерения (1.0), возможно ли это? не является ли косвенно выводимым из объявления my_var: Vector3?

На самом деле 1,0 эквивалентно 1,0 <1>, поэтому вы не можете использовать его в контексте, где ожидается мера, отличная от 1 (безразмерная).

Однако вы можете использовать логический вывод, используя 1.0 <_>.

избегайте использования имени поля записи (как во втором примере). Разве имя поля записи, выводимой самим компилятором, не зависит от порядка?

Самая близкая вещь, о которой я могу подумать, была бы следующей:

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 }

, который затем можно использовать как таковой:

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