Reputation: 41899
Given a List[Foo]
, I apply a function f
.
def f(foo: Foo): Option[Boolean]
I wrote this function body to see if any Foo evaluates to Some(true)
.
val optFalse: Option[Boolean] = Some(false)
val foos: List[Foo] = ...
foos.foldLeft(optFalse){
(acc: Option[Boolean], elem: Foo) => {
val isMatch: Option[Boolean] = f(elem)
optionOr(acc)(match) // takes 2 Option[Boolean] and `or`'s them.
}
}
However, the f
method could be an expensive operation. I'd prefer to "short-circuit":
foos.foldLeft(optFalse){
(acc: Option[Boolean], elem: Foo) => {
if( isTrueOption(acc) ) acc
else {
val isMatch: Option[Boolean] = f(elem)
isMatch
}
}
}
Is there a non-strict way to fold over the entire List[Foo]
, but stop evaluation once one of the Option[Boolean]
equals Some(true)
without my changed code? Perhaps using the =>
operator?
If so, I'm thinking that there's a "space" cost, but I'm not entirely understanding it. Please include that topic as well in your answer (if there is one).
Upvotes: 0
Views: 105
Reputation: 40500
Is this what you are looking for?
foos.reduce {
case (Some(true), _)=> Some(true)
case (_, x) => f(x)
}
Upvotes: 0
Reputation: 17431
It's unclear what role Option
is playing in your code. If you just want to find out whether there's any value for which f
returns Some(true)
, that sounds like a good use case for exists
, which is short-circuit:
foos.exists{x => Some(true) == f(x)}
If you need to know whether any f
returns None
, then clearly you'll need to evaluate the whole list (at least in the case where they're actually all Some
, which is presumably the interesting case).
If it has to be a fold
, then fold
is strict (it would be possible to write a non-strict fold, but that wouldn't be the standard fold
). You could use @Peter's solution in a more structured way by using breakable
.
Upvotes: 1