Я думаю, что метод Run
был добавлен довольно поздно в процессе разработки, так что это, вероятно, причина, почему он отсутствует в документации. Как объясняет desco, метод используется для «запуска» вычислительного выражения. Это означает, что всякий раз, когда вы пишете expr { ... }
, переведенный код будет заключен в вызов к Run
.
Метод немного проблематичен, потому что он нарушает композиционность. Например, разумно требовать, чтобы для любого выражения вычисления следующие два примера представляли одно и то же:
expr { let! a = foo() expr { let! c = expr {
let! b = bar(a) let! a = foo()
let! c = woo(b) let! b = bar(a)
return! zoo(c) } return! woo(b) }
return! zoo(c) }
Однако метод Run
будет вызываться только для общего результата в левом примере и два раза справа (для общего выражения вычисления и для вложенного выражения). Обычная сигнатура типа метода - M<T> -> T
, что означает, что правильный код даже не скомпилируется.
По этой причине рекомендуется избегать этого при создании монад (как они обычно определяются и используются, например, в Haskell), потому что метод Run
нарушает некоторые приятные аспекты монад. Однако, если вы знаете, что делаете, то это может быть полезно ...
Например, в моем коде break
построитель вычислений немедленно выполняет свое тело (в объявлении), поэтому добавление Run
для разворачивания результата не нарушает композиционность - составление означает просто запуск другого кода. Однако определение Run
для async
и других отложенных вычислений вообще не является хорошей идеей.