构建和解构记录

时间:2015-01-06 17:56:46

标签: f#

msdn页面记录Records (F#)详细信息record expressions用于记录构建,record patterns用于解构,后者没有将它们命名为。 这是一个使用两种技术进行算术运算的例子:

// Simple two-dimensional generic vector defintion
type 'a UV =
    { U : 'a; V : 'a }
    static member inline (+) ({ U = au; V = av }, { U = bu; V = bv }) =
        { U = au + bu; V = av + bv }

这显得笨拙且不易阅读。对于解构,有点符号或函数作为替代。由于点符号运算符在规范(an expression’s type may be inferred from a record label)的8.4.2 名称解析和记录字段标签部分中有特殊的分配,因此通常无需注释。像let u { U = u } = u这样的访问器功能不会给我们任何优势。

对于构造,我认为可以将一个函数作为记录构造函数。甚至可能限制对原始构造函数的访问:

type 'a UV =
    internal { U : 'a; V : 'a }
let uv u v = { U = u; V = v }
type 'a UV with
    static member inline (+) (a, b) =
        uv (a.U + b.U) (a.V + b.V)

这是一个惯用的事吗?如何在模块中打包这些函数并处理命名空间问题?

1 个答案:

答案 0 :(得分:5)

简短回答:我认为目前这里没有一般性约定,所以最终将是个人决定。

总结一下您获得的免费以及F#中的记录:

  • 构造:{ U = u; V = v }(括号 - 表示法)

  • 解构:let u = record.u(点符号)和let {U = u} = record(模式匹配)

  • 更新:{record with U = u}(括号 - 表示法)

但如果您希望自己可以手动编写代码,那么您就不会免费获得一流的功能。

以下是我个人使用的惯例:

带有用于记录构造的参数的static member New

对于更新和解构,我会使用某种Lenses抽象。

以下是我必须手动添加的代码示例:

// Somewhere as a top level definition or in a base library
type Lens<'T,'U> = {Get: 'T -> 'U; Set: 'U -> 'T -> 'T } with
  member l.Update f a = l.Set (f (l.Get a)) a


type UV<'a> = {U : 'a; V : 'a } with
// add these static members to your records
  static member New u v : UV<'a> = {U = u; V = v}
  static member u = {Get = (fun (x: UV<'a>) -> x.U); Set = fun t x -> {x with U = t}}
  static member v = {Get = (fun (x: UV<'a>) -> x.V); Set = fun t x -> {x with V = t}}


let uvRecord  = UV.New 10 20
let u         = UV.u.Get uvRecord
let uvRecord1 = UV.u.Set (u+1) uvRecord
let uvRecord2 = UV.u.Update ((+)1) uvRecord

这样我就可以使用第一类函数来构造,解构,但也可以使用更新以及其他非常有趣的镜头属性read in this post

更新(以回应您的评论)

当然,他们可以在以后定义,它会改变什么? 这同样适用于New构造函数,它可以在以后定义,但这实际上是一件好事。 您定义的访问器函数也可以在以后定义,实际上可以在以后定义任何第一类getter,setter或updater值。

无论如何,你的问题的答案是“不,没有约定”,其余的是个人决定,这将是我的决定,而且许多Haskellers正在努力为Haskell记录获得某种自动镜头。

为什么我决定这样走?因为在代码行方面,添加简单访问器功能的工作与添加get-Lens几乎相同,因此以相同的价格获得更多功能。

如果您对镜头讨论不满意,请告诉我,我可以将其删除并留下简短的答案,或者如果它混淆而不是澄清,我也可以删除整个答案。

或者我可能误解了你的问题,对我来说,你的问题是关于哪种约定通常用于为记录添加一流的构造函数,getter和setter值。

组合不是镜片的唯一优势,你可以做很多事情,继续阅读它们,它们提供了一个非常有趣的抽象,而且不仅限于记录。