F# "exit early" computation expression?

In attempting to learn more about how computation expressions work, I'm attempting to code a builder that skips the remainder of the expression after evaluating the then block of an if statement, whereupon the workflow itself would evaluate to true . The workflow should return false if none of the if statements evaluated to true .

For example:

let mutable x = 0

let result =
    earlyExit {
        if false then x <- 99
        if true then x <- 33
        if true then x <- 11
    }

Here, result should be true , and x should be 33 .

The closest I've gotten is:

type EarlyExitBuilder () =
    member this.Combine (a, b) = a || b ()
    member this.Delay fn = fn
    member this.Run fn = fn ()
    member this.Zero () = false

... which results in the workflow evaluating to false , and x to 11 .

Is this doable using the syntax in my example?


The smallest change that would give you the behaviour that you are looking for is probably to add return to the computation - the return construct can return true and terminate the evaluation early:

let mutable x = 0

let result =
    earlyExit {
        if false then return x <- 99
        if true then return x <- 33
        if true then return x <- 11
    }

This evaluates to true and the value of x will be 33 . The computation builder is the same as yours, with additional Return member returning true :

type EarlyExitBuilder () =
    member this.Combine (a, b) = a || b ()
    member this.Delay fn = fn
    member this.Run fn = fn ()
    member this.Zero () = false
    member this.Return( () ) = true

As mentioned in one of the referenced answers, this is somewhat related to my imperative computation builder which lets you use imperative-style return and an extended version with break and continue.


I don't think there's any good way to do this using the syntax you're proposing; inside of a computation expression, something like

if c then e

is going to get compiled to something like

if c then 
    e
    builder.Zero() 
else 
    builder.Zero()

so there's no way for the context to differentiate which branch was taken.

链接地址: http://www.djcxy.com/p/24424.html

上一篇: 作为计算生成器的对象表达式

下一篇: F#“​​退出早期”计算表达式?