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.
加载中,请稍侯......
精彩评论