构建和解构记录

kae*_*fer 2 f#

msdn页面记录record expressions了记录构造和record patterns解构的记录(F#)细节,后者没有将它们命名为.这是一个使用两种技术进行算术运算的示例:

// 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 }
Run Code Online (Sandbox Code Playgroud)

这看起来很笨拙,而且不太可读.对于解构,有点符号或函数作为替代.由于点符号运算符在spec()的8.4.2 名称解析和记录字段标签部分中有特殊的分配an expression’s type may be inferred from a record label,因此通常无需注释.因此,访问器功能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)
Run Code Online (Sandbox Code Playgroud)

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

Gus*_*Gus 5

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

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

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

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

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

但是,如果您希望自己可以手动编写代码,那么您无需免费获得头等功能.

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

A static member New用于记录构造的参数.

对于更新和解构,我会使用某种镜头抽象.

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

// 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
Run Code Online (Sandbox Code Playgroud)

这样我就可以获得构造,解构的一流函数,还有更新以及其他非常有趣的镜头属性,你可以在这篇文章中看到.

更新 (回应您的评论)

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

无论如何,你的问题的答案是"不,没有惯例",其余的是个人决定,这将是我的决定,而且许多Haskellers正在推动为Haskell记录获得某种自动镜头.

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

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

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

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