Екзистенциални типове в Scala

Моля, вижте по-долу кратък пример, който ме озадачава.

Трябва да призная, че имам известни затруднения да манипулирам екзистенциални типове в Scala.

Как трябва да реша реда 56 за несъответствие на типа? proposer е OK тип _$1, докато proposers е от тип _$1 ‹: Индивидуално

Благодаря предварително,

Максим.

class Individual(n: String) {
  protected val name=n
  var preferred: Individual = this
  override def toString(): String=name
}

class Man(n: String) extends Individual(n) { }

class Woman(n: String) extends Individual(n) { }

class Marriage(m: Man, w: Woman){
  private val man=m
  private val woman=w
  def this(w: Woman, m: Man) = this(m,w)
  override def toString(): String = man+"--"+woman
}

class Matching(){
  private var list: List[Marriage] = Nil
  def add(m: Marriage): Unit = { list = m ::list }
  override def toString(): String= {
    var s: String = ""
    for (elm<-list) s=s+elm+" "
    return s
  }
}

object Test{
  protected var male = true

  def main(args: Array[String]): Unit = {
    val al      = new Man("Al")
    val bob     = new Man("Bob")
    val alice   = new Woman("Alice")
    val barbara = new Woman("Barbara")

    al.preferred      = alice
    bob.preferred     = barbara
    alice.preferred   = bob
    barbara.preferred = al

    val men   = Set(al, bob)
    val women = Set(alice, barbara)

    val m = new Matching()
    //var proposers=women

    var proposers: Set[_ <:Individual] = Set[Individual]()
    if (male) proposers = men
    else proposers = women

    while (!proposers.isEmpty) {
      for(proposer <- proposers) {
        val proposer=proposers.head
        if (proposer.isInstanceOf[Man])
          m.add(new Marriage(
            proposer.asInstanceOf[Man],
            proposer.preferred.asInstanceOf[Woman]
          )) 
        else 
          m.add(new Marriage(
            proposer.asInstanceOf[Woman],
            proposer.preferred.asInstanceOf[Man]
          ))
        proposers-=proposer//There is an error here
      } 
    }

    println(m)
  }
}

person maxime.morge    schedule 03.02.2014    source източник
comment
Какъв е въпросът? Може ли изрично да посочите какво не сте разбрали по-горе.   -  person Jatin    schedule 03.02.2014
comment
Как да разрешим несъответствието на типа ред 56? Някаква идея ?   -  person maxime.morge    schedule 03.02.2014
comment
Можете ли да коментирате във вашия код, където има грешка   -  person Jatin    schedule 03.02.2014
comment
Списък, който е ковариантен, трябва да бъде предпочитан пред Set, който не е. Затова използвам var proposers: List[Individual] = List[Individual]() и proposers=proposers.filterNot(p=›p==proposer). Работи.   -  person maxime.morge    schedule 03.02.2014
comment
работи е силно твърдение, всичко, което направихте, беше да разрешите грешката при компилирането. За да работи наистина, трябва също така да може да се поддържа, което означава, че трябва да напреднете отвъд простото писане на Java с извод.   -  person Kevin Wright    schedule 03.02.2014
comment
Вероятно това е днешният политически климат, но това изглежда като ужасно натоварен въпрос :)   -  person Mysterious Dan    schedule 03.02.2014


Отговори (1)


Този код е объркан. Той е зле форматиран, смесва раздели и интервали и използва променливост дори на най-тривиалните места, където функционалното решение изисква малко обмисляне.

Този код също така няма да се прилага в международен план за страни, където еднополовите бракове са възможни.

Работейки отгоре надолу...

Подозирам, че никога няма да искате директно да създадете Individual, а само Man или Woman. Така че алгебричният тип данни има повече смисъл, това се прави с подтипове sealed trait и case class.

Също така ще премахна свойството preferred, тъй като може да доведе до кръгови препратки. Справянето с това в неизменни данни е отвъд нивото, което съм готов да отида в този отговор.

sealed trait Individual {
  def name: String
  override def toString(): String=name
}

//as it's a case class, `name` becomes a val,
//which implements the abstract `def name` from the trait
case class Man(name: String) extends Individual

case class Woman(name: String) extends Individual

Marriage също може да бъде клас case и нека изоставим тромавото дублиране на параметри на класа във vals - това е просто безсмислен шаблон. Това също е добър момент да преместите спомагателния конструктор към фабричен метод в придружаващия обект:

case class Marriage(man: Man, woman: Woman) {      
  override def toString(): String = man + "--" + woman
}
object Marriage {
  def apply(w: Woman, m: Man) = new Marriage(m,w)
}

Matching е почти безсмислено, цял клас само за да обвие List? Подобни неща имаха смисъл в Java преди Generics, но вече не. Все пак ще го запазя (засега), за да мога да поправя това изпълнение на toString, което е болезнено променливо и използва return без основателна причина:

case class Matching(){
  private var list: List[Marriage] = Nil
  def add(m: Marriage): Unit = { list ::= m }
  override def toString() = list.mkString(" ")
}

И накрая, "месото" на проблема. Коментарите са вградени, но ще забележите, че не се нуждая (или не използвам) Matching. Заменя се изцяло от крайния println

object Test{
  //better name, and a val (because it never changes)
  protected val menPropose = true

  def main(args: Array[String]): Unit = {

    // `new` not required for case classes
    val al      = Man("Al")
    val bob     = Man("Bob")
    val alice   = Woman("Alice")
    val barbara = Woman("Barbara")

    // remember how preference was removed from `Individual`?
    val mprefs = Map( al -> alice, bob -> barbara )
    val fprefs = Map( alice -> bob, barbara -> al )

    val men   = Set(al, bob)
    val women = Set(alice, barbara)

    // nicely immutable, and using the returned value from if/else
    val proposers = if (menPropose) men else women

    // no while loop, name shadowing, or mutability.
    // just a simple for-comprehension
    val marriages = for(proposer <- proposers) yield {
      //pattern-matching beats `isInstanceOf`... every time
      proposer match {
        case m: Man => Marriage(m, mprefs(m))
        case f: Woman => Marriage(f, fprefs(f))
      }
    }

    println(marriages mkString " ")
  }
}

Има още, което може да се направи тук, много повече. Ами еднополовите връзки? Ами ако двама или повече души споделят едно и също предпочитание? Ами ако някой няма предпочитания?

Мога също така да кодирам типа на нечие предпочитание в Individual екземпляра. Но това става малко по-напреднало.

person Kevin Wright    schedule 03.02.2014