Какова цель "сделать!" запись в F #? - PullRequest
19 голосов
/ 16 апреля 2010

Я новичок в F #, поэтому это простой вопрос и, возможно, дубликат, но я нигде не смог найти ответ ...

Я читаю эту реализацию LOGO DSL и я не понимаю, что означает «делай!»запись здесь:

    this.Loaded.Add (fun _ ->
        async {
            do! Async.Sleep 200
            for cmd in theDrawing do
                do! this.Execute(cmd)
        } |> Async.StartImmediate 
    )

Можете ли вы помочь?

Ответы [ 3 ]

20 голосов
/ 18 апреля 2010

Я только добавлю, что нотация do! не должна явно поддерживаться выражением вычисления, потому что то же самое можно записать с использованием let!, например так:

do! foo()       // Using do!
let! _ = foo()  // Equivalent using let!

Обычно let! используется, когда у вас есть функция, реализованная с использованием выражений вычислений, и вы хотите вызывать ее из другого выражения вычислений того же типа. Это означает, что он используется для составления вычислительных выражений. Для async эта композиция означает, что у вас есть неблокирующий асинхронный код и вы вызываете его из другого асинхронного рабочего процесса особым образом, чтобы сделать вызов асинхронным.

Ключевое слово let! позволяет вам сделать это и получить какое-то значение в качестве результата, тогда как do! - это ярлык, который вы можете использовать, если вычисление ничего не возвращает.

Глава из функционального программирования реального мира, в которой обсуждаются выражения вычислений (а также выражения последовательностей), доступна в качестве бесплатного примера, поэтому, если вы хотите прочитать более подробное руководство по выражениям вычислений , это может хороший источник информации:

Кстати: должна быть возможность написать пример кода в вашем вопросе лучше, используя примитив AwaitEvent, подобный следующему:

async { 
  let! _ = this.Loaded |> Async.AwaitEvent 
  do! Async.Sleep 200 
  for cmd in theDrawing do 
     do! this.Execute(cmd)  } |> Async.StartImmediate  

Это означает то же самое - сначала он ждет, пока не произойдет событие Loaded, затем он ждет 200 мс, а затем выполняет остальную работу. Это ожидание является особенным (поэтому мы используем let! / do!, потому что оно не блокирует поток во время ожидания).

9 голосов
/ 16 апреля 2010

F # вычислительные выражения (a.k.a. "рабочие процессы") используют синтаксис

builder { expression }

, где expression может содержать специальные конструкции, включая различные ключевые слова "bang", такие как let! и do!. Как и LINQ в C # или VB, выражения для вычислений F # являются просто синтаксическим сахаром (который десагарсируется в вызовах методов на builder).

Одним из наиболее распространенных типов вычислительных выражений является async, как описано здесь .

В этом конкретном примере async используется вместе с Async.Sleep для временного выхода из потока пользовательского интерфейса, чтобы дать возможность пользовательскому интерфейсу перерисовывать, реагировать на события мыши и т. Д. Этот общий метод описан более здесь .

3 голосов
/ 16 апреля 2010

В вашем случае он выполняет асинхронное выражение сна, поэтому поток может делать что-то полезное, а не блокировать.

Как правило, let!, use!, yield! и do! выполняют «специальную» обработку содержащихся в них выражений вычислений (что бы это ни было, async в данном случае). Например. в seq { ... } использование yield! позволяет объединять подпоследовательность с выходом, а не возвращать как один объект.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...