2014-12-09 84 views
3

我有一个关于在F#中使用do块的约定的问题。主要是在使用.NET库类和其他.NET代码时出现这种情况。F#在do块中打包语句

让我给你举个例子。

1.用做块周围包裹的语句:

let drawHelloName (width:int, height:int) name = 
    let bmp = new Bitmap(width, height) 
    use fnt = new Font("Arial", 12.0f) 
    use gr = Graphics.FromImage(bmp) 
    do 
     gr.Clear(Color.White) 
     gr.DrawString(name, fnt, Brushes.Black, PointF(10.0f, 10.0f)) 
    bmp 

2.如果没有做块:

let drawHelloName (width:int, height:int) name = 
    let bmp = new Bitmap(width, height) 
    use fnt = new Font("Arial", 12.0f) 
    use gr = Graphics.FromImage(bmp) 
    gr.Clear(Color.White) 
    gr.DrawString(name, fnt, Brushes.Black, PointF(10.0f, 10.0f)) 
    bmp 

现在在我的心目中,我觉得例1更清晰更多的是F#的观点和风格。由于在函数式编程中处理语句并不是很“自然”,所以我们明确地将这些语句封装在do块中以表明它们是副作用。但我想知道,关于这个的公约是什么?

+0

虽然一个独立的方法调用出现在C#和F#一样,F#断言,这样的调用返回'unit',这使得'do'在许多情况下是多余的。 – Daniel 2014-12-09 14:55:21

回答

7

由于在函数式编程中处理语句并不真正“自然”,所以我们明确地将语句包装在do块中以显示它们是副作用。

我同意你的意见。但是,如果你在野外研究F#代码,他们在这件事上往往会松动。没有严格的惯例,只要按照您认为最适合您的方式行事即可。

另一点是块是否为我们希望明确控制其生命期的值创建新的范围。例如,如果您想提前处置gr并继续使用fnt,你的第一个功能可以被写入:

let drawHelloName (width:int, height:int) name = 
    let bmp = new Bitmap(width, height) 
    use fnt = new Font("Arial", 12.0f) 
    do 
     use gr = Graphics.FromImage(bmp) 
     gr.Clear(Color.White) 
     gr.DrawString(name, fnt, Brushes.Black, PointF(10.0f, 10.0f)) 
    (* Continue to do something with 'fnt' *) 
    bmp 

,你必须使用do块的另一个地方是隐式的构造函数里面例如

type T(width, height) = 
    let bmp = new Bitmap(width, height) 
    use fnt = new Font("Arial", 12.0f) 
    use gr = Graphics.FromImage(bmp) 
    do 
     gr.Clear(Color.White) 
     gr.DrawString(name, fnt, Brushes.Black, PointF(10.0f, 10.0f)) 
+1

唉,F#规范中没有定义“do block”。我们在模块和主要构造函数中都有'do语句',后者甚至是'static do'。数值或函数定义中的“do”行为似乎等同于“加了括号的表达式”或“块表达式”(参见§6.5.1括号和表达式_),但没有人会将它们与副作用联系起来。 – kaefer 2014-12-09 15:18:58

+0

@kaefer究竟是什么区别? – 2014-12-09 17:37:01

+0

区别在于'unit'类型的声明。另外,'type X()= do 1'会得到一个编译错误,而'Y = do 1'或'let z = do 1'只是警告 – kaefer 2014-12-09 21:17:02