Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 记录F的变化#_F#_Type Providers - Fatal编程技术网

F# 记录F的变化#

F# 记录F的变化#,f#,type-providers,F#,Type Providers,我想要一些定义相关记录的方法。比如说, type Thing = { field1: string; field2: float } type ThingRecord = { field1: string; field2: float; id: int; created: DateTime } 或 以及一种从一个转换到另一个的方法,而不需要编写太多的样板文件。即使是第一个完整的例子: type Thing = { field1: string field2: float

我想要一些定义相关记录的方法。比如说,

type Thing       = { field1: string; field2: float }
type ThingRecord = { field1: string; field2: float; id: int; created: DateTime }

以及一种从一个转换到另一个的方法,而不需要编写太多的样板文件。即使是第一个完整的例子:

type Thing =
  { field1: string
    field2: float }
  with
    member this.toThingRecord(id, created) =
      { field1 = this.field1
        field2 = this.field2
        id = id
        created = created } : ThingRecord
and ThingRecord =
  { field1: string
    field2: float
    id: int
    created: DateTime }
  with
    member this.toThing() =
      { field1 = this.field1
        field2 = this.field2 } : Thing
当你到达
field10
等时,这就成了一种负担

目前,我使用反射以一种不安全(且缓慢)的方式进行此操作

我添加了一个请求,要求扩展
语法,以便在uservoice上记录定义,这将满足这一需求


但是否已经有了一种类型安全的方法来实现这一点?可能使用类型提供程序?

为什么不让它们更加嵌套,如下所示

type Thing       = { Field1: string; Field2: float }
type ThingRecord = { Thing : Thing; Id: int; Created: DateTime }

转换函数非常简单:

let toThingRecord id created thing = { Thing = thing; Id = id; Created = created }
let toThing thingRecord = thingRecord.Thing
用法:

> let tr = { Field1 = "Foo"; Field2 = 42. } |> toThingRecord 1337 (DateTime (2016, 6, 24));;

val tr : ThingRecord = {Thing = {Field1 = "Foo";
                                 Field2 = 42.0;};
                        Id = 1337;
                        Created = 24.06.2016 00:00:00;}
> tr |> toThing;;
val it : Thing = {Field1 = "Foo";
                  Field2 = 42.0;}
是的,这是F#的闪光盔甲上的一个裂缝。我觉得没有一个通用的解决方案可以轻松地继承或扩展记录。毫无疑问,人们对这一点很感兴趣——我已经统计了十几份uservoice的意见书,它们都在倡导这方面的改进——这里有一些领先的意见,请随意投票支持:、、

当然,你可以做一些事情来解决这个问题,根据你的情况,这些事情可能对你非常有用。但归根结底,它们是变通办法,你必须牺牲一些东西:

  • 使用反射时的速度和类型安全性
  • 简洁性当您采用类型安全的方式,并拥有完整的记录,记录之间具有转换功能时
  • 当您决定退回到普通的.NET类和继承时,记录提供给您的所有语法和语义好处都是免费的
类型提供程序不会削减它,因为它们不是元编程的好工具。这不是他们设计的目的。如果你试图这样使用它们,你肯定会遇到一些限制

首先,您只能提供基于外部信息的类型。这意味着,虽然您可以拥有一个类型提供程序,该提供程序可以通过反射从.NET程序集中拉入类型,并在此基础上提供一些派生类型,但您不能“内省”正在构建的程序集。因此,无法从同一程序集中先前定义的类型派生

我想您可以通过围绕类型提供程序构建项目来解决这个问题,但这听起来很笨拙。即使这样,也不能提供记录类型,所以最好是普通的.NET类


对于为数据库提供某种ORM映射的更具体的用例,我想您可以很好地使用类型提供程序。只是不是一般的元编程工具。

理想情况下,是的,但数据库不喜欢这样,而且(甚至理想情况下)有时当您真正表示一个平面对象时,使用嵌套结构感觉很奇怪。有时,一些横切的东西使嵌套成为不可能。e、 g.当嵌套时,
WithId
将不同于
Bummer,如果没有现有的解决方案,我计划下周这样做,但类型提供程序不支持记录类型这一(令人惊讶的)事实在一定程度上扼杀了这一想法。如果你有两周的时间,你可以让类型提供程序发出记录类型;)完全愿意,但节省了我几天时间:我从哪里开始呢?您需要对F#compiler生成记录类型所做的工作进行反向工程,并执行同样的操作。最后一部分可能有点棘手——如果它意味着扩展类型提供程序中可用的API的话。不确定是否可以在提供的类型上放置任意属性。从来没有自己编写过复杂的类型提供程序(是的,我曾经考虑过使用类型提供程序进行元编程一次)。
let toThingRecord id created thing = { Thing = thing; Id = id; Created = created }
let toThing thingRecord = thingRecord.Thing
> let tr = { Field1 = "Foo"; Field2 = 42. } |> toThingRecord 1337 (DateTime (2016, 6, 24));;

val tr : ThingRecord = {Thing = {Field1 = "Foo";
                                 Field2 = 42.0;};
                        Id = 1337;
                        Created = 24.06.2016 00:00:00;}
> tr |> toThing;;
val it : Thing = {Field1 = "Foo";
                  Field2 = 42.0;}