scala trait членове и производни променливи

Здравейте, опитвам се да напиша прост алгоритъм за изкачване на хълм в scala.

Имам State и HillClimbing, които са черти. Определям ги като конкретни класове, когато ги прилагам към проблема Graph.

В GraphHillClimbing получавам две грешки. Това е така, защото използвам GraphState вместо State (забележете, че GraphState също е State).

Как мога да разреша това?

trait State {

  val loc = 0

  def neighbours: List[State]

  def get_loc():Int = return loc

}


class GraphState(loc:Int, g: Map[Int, List[Int]]) extends State {

  def neighbours():List[GraphState] =
  {
    def neighboursAcc(l:List[Int], acc:List[GraphState], g:Map[Int, List[Int]]):List[GraphState] =
    {
      if(l.isEmpty) acc
      else {
        val new_neig = new GraphState(l.head, g)
        neighboursAcc(l.tail, List(new_neig) ++ acc, g)
      }
    }
    neighboursAcc(g(loc), List(), g)
  }

}


trait HillClimbing {

  val max_iteration = 4
  val start:State

  def cost(state:State):Double

  private def argmin(costs:List[Double]):Int = {
    val best = costs.min
    costs.indexOf(best)
  }

  private def next_best(states:List[State]):State = {
    val costs = states map(x => cost(x))
    val pos = argmin(costs)
    states(pos)
  }

  def minimize():State = {
    def minimizeAcc(iteration:Int, state:State):State =
    {
      if(iteration > max_iteration) state
      else {
        val neigs = state.neighbours
        val next_state = next_best(neigs)
        minimizeAcc(iteration+1, next_state)
      }
    }
    minimizeAcc(0, start)
  }

}


class GraphHillClimbing(start:GraphState, goal:GraphState) extends HillClimbing {

   // ERROR 1 = start was State and now it is GraphState
   // ERROR 2 = cost should take a State

   def cost(current_state:GraphState):Double = {
     val distance = goal.get_loc() - current_state.get_loc()
     if(distance > 0 ) distance
     else -distance
   }


}



object RunHillClimbing {
  def main(args: Array[String]) {


    val G = Map[Int, List[Int]](1->List(2, 4, 5), 2->List(1, 3, 4), 3->List(2, 6), 4->List(1, 2, 5), 5->List(1, 4), 6->List(3))

    val start = new GraphState(1, G)
    val goal = new GraphState(6, G)

    val hc = new GraphHillClimbing(start, goal)
    print(hc.minimize())

  }
}

person Donbeo    schedule 18.08.2015    source източник


Отговори (2)


Мисля, че това може да бъде решено с помощта на някои параметри на типа с граници на типа.

Също така във вашия конструктор за GraphHillClimbing трябва да използвате val, за да посочите, че параметърът start е конкретната реализация на абстрактното start.

trait State[+Self] {
  Self =>
  def loc:Int

  def neighbours: List[Self]

  def get_loc():Int = return loc
}

class GraphState(val loc:Int, g: Map[Int, List[Int]]) extends State[GraphState] {

  def neighbours():List[GraphState] =
  {
    def neighboursAcc(l:List[Int], acc:List[GraphState], g:Map[Int, List[Int]]):List[GraphState] =
    {
      if(l.isEmpty) acc
      else {
        val new_neig = new GraphState(l.head, g)
        neighboursAcc(l.tail, List(new_neig) ++ acc, g)
      }
    }
    neighboursAcc(g(loc), List(), g)
  }
}

trait HillClimbing[T<:State[T]] {
  val max_iteration = 4
  val start:T

  def cost(state:T):Double

  private def argmin(costs:List[Double]):Int = {
    val best = costs.min
    costs.indexOf(best)
  }

  private def next_best(states:List[T]):T = {
    val costs = states map(x => cost(x))
    val pos = argmin(costs)
    states(pos)
  }

  def minimize():T = {
    def minimizeAcc(iteration:Int, state:T):T =
    {
      if(iteration > max_iteration) state
      else {
        val neigs = state.neighbours
        val next_state = next_best(neigs)
        minimizeAcc(iteration+1, next_state)
      }
    }
    minimizeAcc(0, start)
  }
}

class GraphHillClimbing(val start:GraphState, goal:GraphState) extends HillClimbing[GraphState] {

  def cost(current_state:GraphState):Double = {
    val distance = goal.get_loc() - current_state.get_loc()
    if(distance > 0 ) distance
    else -distance
  }
}

object RunHillClimbing {
  def main(args: Array[String]) {

    val G = Map[Int, List[Int]](1->List(2, 4, 5), 2->List(1, 3, 4), 3->List(2, 6), 4->List(1, 2, 5), 5->List(1, 4), 6->List(3))

    val start = new GraphState(1, G)
    val goal = new GraphState(6, G)

    val hc = new GraphHillClimbing(start, goal)
    print(hc.minimize())
  }
}
person mattinbits    schedule 18.08.2015
comment
Благодаря за отговора, но с вашия код получавам една грешка: Error:(1, 16) trait State takes type parameters trait State[T<:State] { ^ - person Donbeo; 18.08.2015
comment
благодаря работи. Имате ли препратка към синтаксиса Self =›? - person Donbeo; 18.08.2015
comment
stackoverflow.com/questions/23562845/ - person mattinbits; 18.08.2015

Какво получавам:

error: class GraphHillClimbing needs to be abstract, since:
it has 2 unimplemented members.
/** As seen from class GraphHillClimbing, the missing signatures are as follows.
*  For convenience, these are usable as stub implementations.
*/
  def cost(state: this.State): Double = ???
  val start: this.State = ???

class GraphHillClimbing(start:GraphState, goal:GraphState) extends HillClimbing {
      ^

Заменете GraphState в класа с State, тъй като наследяването изисква да управлявате State, а не GraphState.

След това сменете

 val loc = 0

с

 def loc = 0

Така че можете да го презапишете в GraphState.

person Reactormonk    schedule 18.08.2015
comment
Искам да започна да бъда GraphState, защото може да има повече функционалност от състояние - person Donbeo; 18.08.2015
comment
@Donbeo тогава не можете да разширите HillClimbing или ще трябва да специализирате HillClimbing, за да използвате GraphState вместо State. - person Reactormonk; 18.08.2015