【问题标题】:Returning the same type the function was passed返回与传递函数相同的类型
【发布时间】:2011-02-20 04:20:57
【问题描述】:

我有以下广度优先搜索的代码实现。

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 传递LeftSideOfRiver 的实例时,我怎样才能使类型起作用,以便breadthFirstSearch 推断出正确的返回类型是CannibalsState

这可以用抽象类型成员完成,还是必须用泛型完成?

【问题讨论】:

    标签: scala types type-systems


    【解决方案1】:

    这个怎么样?

    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
      }
    }
    

    【讨论】:

      【解决方案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 {
          // ...
        }
      
      }
      

      【讨论】:

        【解决方案3】:

        一种选择是使用 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 {
             //...
            }
        
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-12-24
          • 1970-01-01
          • 2016-08-09
          • 2014-05-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-12-23
          相关资源
          最近更新 更多