宣布F#4.6预览

   原文

我们很高兴地宣布Visual Studio 2019将在它发布时推出新版本的F#:F#4.6!

F#4.6是对F#语言的较小更新,使其成为“真正的”点发布。与之前版本的F#一样,F#4.6完全通过开放的RFC(评论请求)过程开发。 F#社区在讨论此版本语言时提供了非常详细的反馈。您可以在此处查看与此版本对应的所有RFC:

这篇文章将详细介绍功能集以及如何入门。

开始吧

首先,安装:

接下来,将FSharp.Core依赖项更新为FSharp.Core 4.6(或更高版本)。如果您使用的是Visual Studio,则可以使用NuGet包管理UI执行此操作。如果您不使用Visual Studio,或者更喜欢手工编辑项目文件,请将其添加到项目文件中:

一旦安装了必要的位,就可以在Visual StudioVisual Studio for Mac带有Ionide的Visual Studio Code中使用F#4.6。

匿名记录

除了各种错误修复,F#4.6中唯一的语言更改是引入匿名记录类型

基本用法

从F#-only的角度来看,Anonymous Records是F#记录类型,没有明确的名称,可以在ad-hoc fasion中声明。尽管它们不太可能从根本上改变您编写F#代码的方式,但它们确实填补了F#程序员随着时间的推移遇到的许多较小的空白,并且可以用于以前无法实现的简洁数据操作。

它们很容易使用。例如,在这里您可以如何与产生匿名记录的函数进行交互:

但是,它们不仅可用于基本数据容器。以下扩展了上一个示例以使用更安全类型的打印功能:

如果您尝试使用具有相同基础数据类型但标签不同的匿名记录调用`printCircleStats`,则无法编译:

这正是F#记录类型的工作方式,除了一切都是临时声明而不是预先声明。根据您的具体情况,这有利有弊,因此我们建议明智地使用匿名记录,而不是替换所有前期F#记录声明。

结构匿名记录

匿名记录也可以使用struct关键字进行结构化

你可以调用一个带结构匿名记录的函数,可以这样明确地完成:

或者您可以使用“structness inference”来忽略调用站点上的`struct`:

这会将您创建的匿名记录的实例视为结构。

请注意,反之则不然:

目前无法定义IsByRefLikeIsReadOnly结构匿名记录类型。有一种语言建议提出了这种增强,但由于语法上的奇怪,它仍在讨论中。

更进一步

匿名记录可用于更广泛的更高级的上下文中。

匿名记录是可序列化的

您可以序列化和反序列化匿名记录:

这会输出您可能期望的内容:

这是一个在另一个项目中调用的示例库:

这可以使诸如轻量级数据在由微服务组成的系统中通过网络的情况更容易。

匿名记录可以与其他类型定义组合使用

您的域中可能有类似树的数据模型,例如以下示例:

通常会将案例建模为具有命名联合字段的元组,但随着数据变得越来越复杂,您可以使用记录提取每个案例:

如果适合您的代码库,现在可以使用匿名记录缩短此递归定义:

与前面的示例一样,应该明智地应用此技术,并在适用于您的方案时应用。

匿名记录简化了F#中LINQ的使用

在处理数据时,F#程序员通常更喜欢使用List,Array和Sequence组合器,但有时使用LINQ会有所帮助。传统上这有点痛苦,因为LINQ使用C#匿名类型。

使用匿名记录,您可以像使用C#和匿名类型一样使用LINQ方法:

这打印:

匿名记录可以轻松使用Entity Framework和其他ORM

使用F#查询表达式与数据库交互的F#程序员应该看到一些使用匿名记录的生活质量改善。

例如,您可能习惯使用元组使用`select`子句对数据进行分组:

但是这导致名称如Item1Item2的列不理想。在匿名记录之前,您需要声明记录类型并使用它。现在你不需要这样做:

不需要预先指定记录类型!这使得查询表达式与它们建模的实际SQL更加一致。

匿名记录还允许您避免必须在更高级的查询中创建AnonymousObject类型,只是为了查询的目的创建ad-hoc数据分组。

匿名记录可以简化ASP.NET Core中自定义路由的使用

您可能已经在使用带有F#的ASP.NET Core,但在定义自定义路由时可能会遇到尴尬。与前面的示例一样,这仍然可以通过预先定义记录类型来完成,但F#开发人员通常认为这是不必要的。现在你可以内联:

它仍然不理想,因为F#对返回类型是严格的(与C#不同,你不需要显式地忽略返回值的东西)。但是,这确实允许您删除以前定义的记录定义,这些定义除了允许您将数据发送到ASP.NET中间件管道之外没有其他用途。

使用匿名记录复制和更新表达式

与记录类型一样,您可以将复制和更新语法与匿名记录一起使用:

但是,复制和更新表达式不会将生成的匿名记录限制为相同类型:

原始表达式也可以是记录类型:

您还可以在引用和结构匿名记录之间复制数据:

使用复制和更新表达式可以在使用F#中的数据时为匿名记录提供高度的灵活性。

平等和模式匹配

匿名记录在结构上是等同的并且具有可比性:

但是,要比较的类型必须具有相同的“形状”:

虽然您可以将匿名记录等同并进行比较,但您无法对它们进行模式匹配。这有两个原因:

  • 与记录类型不同,模式必须考虑匿名记录的每个字段。这是因为匿名记录不支持结构子类型 - 它们是名义类型。
  • 模式匹配表达式中没有其他模式的能力,因为每个不同的模式都意味着不同的匿名记录类型。
  • 考虑匿名记录中每个字段的要求将使得模式比使用“点”符号更加冗长。

相反,“dot”-syntax用于从匿名记录中提取值。这总是最多如同使用模式匹配一样冗长,并且由于不总是从匿名记录中提取每个值,实际上可能不那么冗长。以下是如何使用先前的示例,其中匿名记录是受歧视联合的一部分:

目前有一个开放的建议是允许在有限的上下文中对匿名记录进行模式匹配,以便实际启用它们。如果您有一个建议的用例,请使用该问题进行讨论!

FSharp.Core补充

如果不添加F#核心库,它将不会是另一个F#版本!

ValueOption扩展

F#4.5中引入的ValueOption类型现在还有一些附加到该类型的好东西:

  • DebuggerDisplay属性有助于调试
  • IsNoneIsSomeNoneSomeop_ImplicitToString成员

这使它与Option类型“奇偶校验”。

此外,现在有一个ValueOption模块包含`Option`模块具有的相同功能:

这应该可以缓解“ValueOption”是“Option”的奇怪兄弟所带来的任何问题,它们没有获得相同的功能集。

tryExactlyOne用于List,Array和Seq

这个精细的功能是由Grzegorz Dziadkiewicz贡献的。以下是它的工作原理:

包起来

尽管F#4.6中的功能总列表并不多,但它们仍然非常深入!我们鼓励您尝试F#4.6并给我们反馈,以便我们可以在完整版本之前对内容进行微调。一如既往,感谢F#社区在代码和设计讨论方面的贡献,这有助于我们继续推进F#语言。

干杯,快乐的黑客!