2019 年 9 月 23 日,F# 4.7 发布,这次更新为 F# 语法加入了更多的甜味。
隐式 yield
在之前的版本中定义 seq
块的时候,我们必须给每个返回值的前面加上 yield
关键字。F# 4.7 改进了这一点,在 seq
块中再也不必每行起手就是一个 yield
了。
// F# 4.6 and lower
let nums =
seq {
yield 1
yield 2
yield 3
}
// F# 4.7 and higher
let nums' =
seq {
1
2
3
}
除了 seq
之外,任何支持 Yield
,Combine
,Delay
和 Zero
的 CE(Computation Expression)中的 yield
也可以隐式的使用。
但这并不是隐式 yeild
的全部,List、Array 的字面量定义中也可以使用隐式 yield 这一特性!再过去,如果你想要在列表的中通过判断某个条件来生成一个值,你就需要为列表中的每一个元素的加上 yield
前缀,而现在,这些重复的关键字终于可以移除掉了。
// F# 4.6 and lower
let f includeWeekend =
[
yield "Monday"
yield "Tuesday"
yield "Wednesday"
yield "Thursday"
yield "Friday"
if includeWeekend then
yield "Saturday"
yield "Sunday"
]
// F# 4.7 and higher
let f' includeWeekend =
[
"Monday"
"Tuesday"
"Wednesday"
"Thursday"
"Friday"
if includeWeekend then
"Saturday"
"Sunday"
]
这对于那些使用 F# 列表创建 HTML 的 DSL 非常有用,例如 Fable、Giraffe。
更宽松的语法
这次更新中放宽了两处语法的书写规范,不仅让新人更容易上手,也简化了代码的输入。
不再需要双下划线
在之前的版本中,如果我们不想定义某个变量的名字,我们必须使用双下划线来抛弃来定义变量名。现在,F# 中可以使用类似 C# 的单下划线来忽略变量的名字了。
for _ in 1..10 do ()
type C'() =
member _.M() = ()
构造函数与静态方法的参数位置放宽
之前的 F# 编译器中,第一个参数的缩进决定了其余参数的缩进,这在编写代码的时候可能会让人感到恼火。
type OffsideCheck(a:int,
b:int, c:int,
d:int) = class end
type C() =
static member M(a:int,
b:int, c:int,
d:int) = 1
现在这个限制被放宽了。
type OffsideCheck'(a:int,
b:int, c:int,
d:int) = class end
type C'() =
static member M(a:int,
b:int, c:int,
d:int) = 1
预览功能
就像 C# 编译器一样,F# 编译器现在支持通过配置开启预览语法了,目前的预览语法主要有两个:nameof
以及 open 静态类。
Nameof
nameof
函数算得上是社区呼声最高的功能之一了,它的作用就跟 C# 中的同名关键字一样,用来获取变量的名称。目前这个功能还不算 100% 的完善,所以仍然需要社区的使用反馈。
open System
let combineLengths (str1: string) (str2: string) =
if isNull str1 then
raise (ArgumentNullException(nameof str1))
elif isNull str2 then
raise (ArgumentNullException(nameof str2))
else
str1.Length + str2.Length
module M =
let f x = x
printfn "%s namespace is opened right now" (nameof System)
printfn "Module %s has a function called %s" (nameof M) (nameof M.f)
open 静态类
在 C# 中,可以通过 using 一个静态类来暴露其中所有的静态方法,这样调用的时候就不必总是加上前缀了。一些 C# 编写的第三库也利用来这个特性来打造出了自己的 DSL,所以在 F# 中,这个特性的需求也非常大。目前 open 静态类的特性也只是作为一个预览功能放出,更完善的设计也需要接收更多社区中的使用者的意见。不过现在我们可以看看用了这个特性的代码长啥样。
open System.Math
let verifyMathWorks () =
printfn "Just verifying that sin(pi) is indeed zero..."
Sin(PI) = 0.0
[<AbstractClass; Sealed>]
type MyStaticClass =
static member L(x: int) = x
static member M(x: int) = x
static member N(x: int) = x
static member O(x: int) = x
static member P(x: int) = x
open MyStaticClass
let x = 12
let xAgain = L(M(N(O(P(x)))))