Something similar to yield break in F#
How to break after first if?
开发者_如何学Golet WithdrawalCash (account, amount) = seq {
if ( account.Balance.CurrentAmount - amount < 0.0m) then
yield NotEnoughMoneyForWithdrawal(account, amount)
// How to break here?
let newBalance = account.Balance.CurrentAmount - amount
yield CashWithdrawnEvent(account, newBalance)
}
Not sure this will help, why not use the else clause?
let WithdrawalCash (account, amount) = seq {
if ( account.Balance.CurrentAmount - amount < 0.0m) then
yield NotEnoughMoneyForWithdrawal(account, amount)
// How to break here?
else
let newBalance = account.Balance.CurrentAmount - amount
yield CashWithdrawnEvent(account, newBalance)
}
Also have a look at:
Imperative computation in F# (II.) - Writing break and continue
The code as posted will only evern return one CashWithdrawlEvent, then end the sequence... you need to have a loop to return multiple values. Also, have you considered using "match" to handle multiple cases?
(not tested as working...)
let WithdrawalCash (account, amount) = seq {
let bDone = ref false
while not (!bDone) do
match amount with
| v when account.Balance.CurrentAmount - v < 0 ->
yield NotEnoughMoneyForWithdrawal(account, amount)
bDone := true // break
// more when clauses can go here
| _ ->
let newBalance = account.Balance.CurrentAmount - amount
yield CashWithdrawnEvent(account, newBalance)
// let the sequence continue
}
But, even this does not seem like what you would want, since it will ALWAYS withdraw the same 'amount' each time you pull a value from the sequence, because account and amount are fixed when the sequence is created. So, I'd drop the 'seq' and make this a simple function, as in:
let WithdrawalCash (account, amount) =
match amount with
| v when account.Balance.CurrentAmount - v < 0 ->
NotEnoughMoneyForWithdrawal(account, amount)
// more when clauses can go here
| _ ->
let newBalance = account.Balance.CurrentAmount - amount
CashWithdrawnEvent(account, newBalance)
For the general case of enumerating some sequence and stopping when a particular condition is met, consider "Seq.takeWhile", as in:
let MySeq = seq {
while true do
yield someValue
}
let code () =
MySeq
|> Seq.takeWhile ( fun v -> ShouldIContinueWorkingTest(v) )
|> Seq.iter ( fun v -> DoWork(v) )
As this is the only relevant question in SO about yield break
in F#, I think I should add this for the sake of completeness. In the OP's question one could get away with the else
. But what do you do if you really need to break? what if you have to deal with match
? Let's assume that you have a discriminated union like this
type SomeUnion =
| Foo of SomeType
| Bar of SomeType * SubclassOfSomeType
| Indifferent of IncompatibleType
and you want to get a sequence of SomeType
and SubclassOfSomeType
and ignore the rest:
let private toSomeType (arg:SomeUnion) =
seq {
match arg with
| Foo foo -> yield foo
| Bar (one, two) -> yield one; yield two
| Indifferent _ -> () (*<- effectively this is your 'yield break'*)
}
I used Indifferent
as it was my only remaining case. Obviously one could simply use | _ -> ()
to ignore a gazillion of cases, I just prefer to see the warning if I add another case in the future.
I hope that this is a correct technique as I am an absolute beginner in F# and I had to chase my tail for some time to get around this. Feel free to let me know in the comments if there is a better way.
精彩评论