2014-12-09 2 views
3

У меня есть вопрос относительно соглашений об использовании блоков do в F #. В первую очередь это возникает при работе с библиотечными классами .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

ответ

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 statements', в модулях и первичных конструкторах, последние - как' static do'. Поведение 'do' внутри значений значений или функций кажется эквивалентным« выражению в скобках »или« блочному выражению »(см. _§6.5.1 Parenthesized и Block Expressions_), но никто не свяжет их с побочными эффектами. – kaefer

+0

@kaefer В чем же разница? –

+0

Разница заключается в утверждении типа 'unit'. Кроме того, 'type X() = do 1' получает ошибку компиляции, тогда как' module Y = do 1' или 'let z = do 1' являются простыми предупреждениями – kaefer