2016-06-11 19 views
4

F#中的'do'关键字的一个更微妙的用途是能够注释返回单元(aka语句)的表达式。例如,我经常在函数定义中这样做,以清楚说明返回类型是单位,并且还指示编译器为我检查此类型。例如:适当的F#中的绑定风格#

let restart agent = do agent.Post Restart 

但是我不确定'do'关键字占主导地位的是F#社区。

什么是使用“做”关键字在这个例子中,正确的方法:

// Annotate each statement 
let move source destination = 
    do copy source destination 
    do clear source 

// Annotate the statements as one block 
let move source destination = 
    do 
     copy source destination 
     clear source 

// Just annotate the "return" statement 
let move source destination = 
    copy source destination 
    do clear source 

// Perhaps don't annotate at all? 
let move source destination = 
    copy source destination 
    clear source 

回答

3

我很少看到F#代码用于此目的(将unit表达式)do。您所描述的大多数类型检测已经在没有它的情况下自动执行,以FS0020关于未使用值的警告形式进行。

如果你简单地写

let move source destination = 
    copy source destination 
    clear source 

然后三种情况之一会发生:

  • 两个copyclear返回unit

    在这种情况下,一切都很好。

  • copy返回除单元

    其他

    在这种情况下一个类型将收到FS0020警告关于忽略值:

    表达copy source destination返回当前正被忽略的int。如果你不需要这个值,你应该使用忽略函数明确地忽略它,例如ignore (copy source destination)或将结果与名称绑定let result = copy source destination

  • copy回报单元,clear返回比unit

    在这种情况下其他类型不会有警告,但move将具有相同类型clear,而这种差异将在调用表现网站为move,你会得到与上面相同的警告。

所以do的类型检查的目的,效用相当有限:仅在过去的情况下,它会有所作为,通过使警告在原线路出现迫使你从move导航到它,而不是' (或可能 - 如果move是其范围中的最后一行 - 从move的呼叫者的呼叫站点等等)。如果clear返回一个值(例如指示清除是否成功的布尔值),那么您肯定会想要将该信息传播到调用链上!

这就是说,这是一个非常简单的标志,(IMO)不会在一定程度上损害可读性,并且可以改进它。考虑到F#社区对喜欢禁用灯语法(#light "off")并手动输入分号和end标记的少数用户没有问题,我无法想象do会在任何地方抬起任何眉毛。

+0

很好的答案!我知道FS0020,但我更喜欢在这种情况下明确表达,尤其是因为单位表达意味着副作用,这迫使您考虑每一个这样的用法,并且引起读者的注意。说到分号,另一种选择可能是:复制源目标;明确的来源 – monoceres