2011-11-23 38 views
2

假设我定义的模块来处理与计量单位向量在F#:简化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. 避免使用记录字段名称(如第二个示例中所示)。基于命令,编译器本身是否可以导出记录的字段名称?

回答

4

避免测量单位规范(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<_>) 
+0

哦thanks..the新的建议是非常有用的.. – Heisenbug

5

我不认为你需要指定类型对于你自己的变量,让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> 
+0

脱节工会的不便,不过,是你可以使用点符号来访问单个字段。您可以通过使用类并为其编写一个活动模式来充分利用这两个世界,但是这会开始形成很多代码,所以如果您有这种情况,您可能不想这样做许多这样的类型来写。 – Tarmil