【问题标题】:Simplify record assignment in F#简化 F# 中的记录分配
【发布时间】:2011-11-23 11:19:11
【问题描述】:

假设我在 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&lt;m&gt;),这可能吗? m 不是可以从声明 my_var : Vector3&lt;m&gt; 隐式推导出来的吗?
  2. 避免使用记录字段名称(如第二个示例)。记录的字段名不是由编译器自己根据顺序推导出来的吗?

【问题讨论】:

    标签: f# record measure


    【解决方案1】:

    我认为您不需要自己指定变量的类型,让 F# 进行类型推断。所以下面的声明就足够了:

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

    如果您不想指定记录字段名称(我认为这有助于使您的程序清晰),您可以将记录更改为类(如@Tarmil 的答案)或不相交的联合。就个人而言,我更喜欢不相交的联合,因为我仍然可以轻松地在模式匹配中使用它们:

    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>
    

    【讨论】:

    • 不相交联合的不便之处在于,您不能使用点符号来访问单个字段。您可以通过使用类并为其编写活动模式来获得两全其美,但是这开始是很多代码,所以如果你有很多这样的类型要编写,你可能不想这样做。
    【解决方案2】:

    避免测量单位规范(1.0),这可能吗? m 不是可以从声明 my_var : Vector3 中隐式推导出来的吗?

    实际上,1.0 等价于 1.0,因此您不能在预期测量值不是 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<_>)
    

    【讨论】:

      猜你喜欢
      • 2013-10-19
      • 1970-01-01
      • 2011-05-01
      • 2014-04-21
      • 2020-10-21
      • 2011-11-27
      • 1970-01-01
      • 1970-01-01
      • 2019-01-10
      相关资源
      最近更新 更多