我有以下广度优先搜索的代码实现。
trait State{
def successors:Seq[State]
def isSuccess:Boolean = false
def admissableHeuristic:Double
}
def breadthFirstSearch(initial:State):Option[List[State]] = {
val open= new scala.collection.mutable.Queue[List[State]]
val closed = new scala.collection.mutable.HashSet[State]
open.enqueue(initial::Nil)
while (!open.isEmpty){
val path:List[State]=open.dequeue()
if(path.head.isSuccess) return Some(path.reverse)
closed += path.head
for (x <- path.head.successors)
if (!closed.contains(x))
open.enqueue(x::path)
}
return None
}
如果我为我的特定问题定义了State
的子类型
class CannibalsState extends State {
//...
}
让breadthFirstSearch
返回与传递相同的子类型的最佳方法是什么?
假设我改变了这一点,以便我的特定问题有3个不同的状态类,并且它们共享一个共同的超类型:
abstract class CannibalsState extends State {
//...
}
class LeftSideOfRiver extends CannibalsState {
//...
}
class InTransit extends CannibalsState {
//...
}
class RightSideOfRiver extends CannibalsState {
//...
}
如何使类型运行起来,以便breadthFirstSearch
在传递CannibalsState
的实例时推断出正确的返回类型为LeftSideOfRiver
?
这可以使用抽象类型成员完成,还是必须使用泛型?
答案 0 :(得分:2)
这个怎么样?
trait State[+S] {
def successors: Seq[State[S]]
def isSuccess: Boolean = false
def admissableHeuristic: Double
}
object BFS
{
def
breadthFirstSearch[S <: State[S]](initial: State[S]): Option[List[State[S]]] = {
val open= new scala.collection.mutable.Queue[List[State[S]]]
val closed = new scala.collection.mutable.HashSet[State[S]]
open.enqueue(initial :: Nil)
while (!open.isEmpty) {
val path: List[State[S]] = open.dequeue()
if (path.head.isSuccess)
return Some(path.reverse)
closed += path.head
for (x <- path.head.successors)
if (!closed.contains(x))
open.enqueue(x :: path)
}
return None
}
}
答案 1 :(得分:2)
解决此类问题的一种方法是将State
特征以及在其他特征中作用于其上的操作括起来。
trait ProblemType {
trait State {
def successors: Seq[State]
def isSuccess: Boolean = false
def admissableHeuristic: Double
}
def breadthFirstSearch(initial: State): Option[List[State]] = {
val open = new scala.collection.mutable.Queue[List[State]]
val closed = new scala.collection.mutable.HashSet[State]
open.enqueue(initial :: Nil)
while (!open.isEmpty) {
val path: List[State] = open.dequeue()
if (path.head.isSuccess) return Some(path.reverse)
closed += path.head
for (x <- path.head.successors)
if (!closed.contains(x))
open.enqueue(x :: path)
}
return None
}
}
然后,您可以在扩展封闭特征的对象中定义具体状态:
object RiverCrossingProblem extends ProblemType {
class LeftSideOfRiver extends State {
// ...
}
class InTransit extends State {
// ...
}
class RightSideOfRiver extends State {
// ...
}
}
答案 2 :(得分:2)
一种选择是使用Randall描述的泛型。如果你想用抽象类型成员实现类似的东西,那么你可以这样做(基于Mitch的代码):
trait ProblemType {
type S <: State
trait State {
def successors: Seq[S]
def isSuccess: Boolean = false
def admissableHeuristic: Double
}
def breadthFirstSearch(initial: S): Option[List[S]] = {
val open = new scala.collection.mutable.Queue[List[S]]
val closed = new scala.collection.mutable.HashSet[S]
open.enqueue(initial :: Nil)
while (!open.isEmpty) {
val path: List[S] = open.dequeue()
if (path.head.isSuccess) return Some(path.reverse)
closed += path.head
for (x <- path.head.successors)
if (!closed.contains(x))
open.enqueue(x :: path)
}
return None
}
}
object RiverCrossingProblem extends ProblemType {
type S = CannibalsState
abstract class CannibalsState extends State {
//...
}
class LeftSideOfRiver extends CannibalsState {
//...
}
class InTransit extends CannibalsState {
//...
}
class RightSideOfRiver extends CannibalsState {
//...
}
}