What's the status of the Run()
method in a computation method? I've seen it in several examples (here, here, here), and I've seen in it F#'s compiler source, yet it's not in the spec or the MSDN documentation. I filed an issue in MS Connect about this and it was closed as "by design" without further explanations.
So is it depreca开发者_开发问答ted/undocumented/unsupported? Should I avoid it?
UPDATE: MS Connect issue status was promptly changed and the MSDN page updated to include Run()
6.3.10 Computation Expressions
More specifically, computation expressions are of the form builder-expr { cexpr } where cexpr is, syntactically, the grammar of expressions with the additional constructs defined in comp-expr. Computation expressions are used for sequences and other non-standard interpretations of the F# expression syntax. The expression builder-expr { cexpr } translates to
let b = builder-expr in b.Run (b.Delay(fun () -> {| cexpr |}C))
for a fresh variable b. If no method Run exists on the inferred type of b when this expression is checked, then that call is omitted. Likewise, if no method Delay exists on > the type of b when this expression is checked, then that call is omitted
I think that the Run
method was added quite late in the development process, so that's probably a reason why it is missing in the documentation. As desco explains, the method is used to "run" a computation expression. This means that whenever you write expr { ... }
, the translated code will be wrapped in a call to Run
.
The method is a bit problematic, because it breaks compositionality. For example, it is sensible to require that for any computation expression, the following two examples represents the same thing:
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) }
However, the Run
method will be called only on the overall result in the left example and two times on the right (for the overall computation expression and for the nested one). A usual type signature of the method is M<T> -> T
, which means that the right code will not even compile.
For this reason, it is a good idea to avoid it when creating monads (as they are usually defined and used e.g. in Haskell), because the Run
method breaks some nice aspects of monads. However, if you know what you are doing, then it can be useful...
For example, in my break
code, the computation builder executes its body immediately (in the declaration), so adding Run
to unwrap the result doesn't break compositionality - composing means just running another code. However, defining Run
for async
and other delayed computations is not a good idea at all.
精彩评论