While the Scala Option
will work here, as the other two answers pointed out, a more idiomatic functional approach would be to use a βlazy listβ - or Stream
, in Scala - to represent a set of solutions.
I found myself such code, for example:
trait Node[A] { def children: Stream[A with Node[A]] def dfs(f: A => Boolean): Stream[A] = this.children.flatMap { child => if (f(child)) Stream(child) else child.dfs(f) } }
Now suppose I have a Board
class that extends Node[Board]
and has an implementation of the children
method that returns all valid boards with one additional part. Suppose it has other useful things, such as the size
method, companion object with empty
, etc.
Then I can write the following to get Stream
solutions:
val solutions = Board.empty.dfs(_.size == 8)
A Stream
lazy and evaluates only his head, so right now we were only looking for a tree far enough to find the first solution. We can get this solution using head
:
scala> solutions.head res1: Board = o . . . . . . . . . . . o . . . . . . . . . . o . . . . . o . . . . o . . . . . . . . . . . o . . o . . . . . . . . . o . . . .
Or whatever. But I can also get other results if I want them:
scala> solutions(10) res2: Board = . o . . . . . . . . . . . . o . . . . . o . . . . . . . . . . o o . . . . . . . . . . o . . . . . . . . . o . . . . o . . . . .
It searches for enough of the whole tree to search for the tenth solution, and then stops.
The big advantage of Stream
over the Option
approach is that I can get additional results if I need them without paying more for the first one.
Travis brown
source share