MyType类型不匹配

时间:2012-09-11 09:57:13

标签: scala types self-type

我从Landei here借用了MyType技巧。但最近我遇到了自我类型的问题。一个例子说明了我的意思:

trait Excitable[SELF] { self: SELF =>
  def withMoreAnger: SELF
}
trait Animal[SELF0] { self: SELF0 =>
  type SELF = SELF0 // to reveal SELF0 for method spitAt used as a dependent method type 
  type SpittableAnimal[S] <: Animal[S]
  def spitAt[A <: SpittableAnimal[_]](a: A): a.SELF
}
trait ExcitableAnimal[SELF] extends Animal[SELF] with Excitable[SELF] { self: SELF =>
  type SpittableAnimal[S] = ExcitableAnimal[S]
  def spitAt[A <: SpittableAnimal[_]](a: A): a.SELF = a.withMoreAnger
}
trait Quadruped[SELF] extends ExcitableAnimal[SELF] { self: SELF => }
case class Dog(anger: Int) extends Quadruped[Dog] {
  def withMoreAnger: Dog = copy(anger = anger + 1)
}
case class Cat(anger: Int) extends Quadruped[Cat] {
  def withMoreAnger: Cat = copy(anger = anger + 1)
}
val dog = Dog(anger = 0)
val cat = Cat(anger = 0)
val angryCat: Cat = dog spitAt cat // fine

val anotherDog = Dog(0)
val animals = Seq(dog, cat)
val angryAnimals: Seq[Quadruped[_]] = for (a <- animals) yield anotherDog spitAt a // fine
val veryAngryAnimals: Seq[Quadruped[_]] = for (a <- angryAnimals) yield anotherDog spitAt a // type mismatch !!!

据我所知,问题似乎是spitAt方法中的下划线最终会为Any产生a.SELF。但是我怎样才能使这段代码有效呢? 我也试过这个:

def spitAt[A <: SpittableAnimal[A]](a: A): A = a.withMoreAnger

但是推断的类型参数不符合方法spitAt的类型参数边界,这对我来说很清楚,因为SELF中元素的animals类型参数至少受{{1}的限制。 }}不符合上面_ >: Cat with Dog <: Quadruped[_]中的a.SELFA,甚至spitAtA的{​​{1}}:

spitAt

那么使def spitAt[A <: SpittableAnimal[S], S <: A](a: A): A = a.withMoreAnger - 循环线有效的spitAt方法的正确签名是什么?
也许SELF类型参数的方差注释(for)可能会有所帮助,但我不知道如何。

3 个答案:

答案 0 :(得分:1)

你喜欢zee疼痛吗?你呢! :)

我不相信这个问题没有爱。

$ smala spit.Test
List(mild puppy, sweet kitteh)
List(angry puppy, gnarly kitteh)
List(angry hound, gnarly pussy)

谁能抵抗这个粗糙的人?

Upvote me或kitteh生气!非常生气!

在关于MyType的问题中,我们发现人们只是说使用类型类。就这么做。

很容易授予那些可能会吐痰并吐口水,也许容易阅读代码的人。

我的意思是聪明,例如,一只非常生气的猫变成了GhostCat(愤怒&gt; 9人的生命),但我必须在幼儿园去司机......

package spit

import language.{ higherKinds, implicitConversions }

trait Excitable[SELF] { self: SELF =>
  def withMoreAnger: SELF
}
trait Animal[SELF] { self: SELF =>
  type SpatAt = SELF
  type SpittableAnimal[S] <: Animal[S]
}
trait ExcitableAnimal[SELF] extends Animal[SELF] with Excitable[SELF] { self: SELF =>
}
object ExcitableAnimal{
  implicit def toSpitter[S](a: ExcitableAnimal[S]) = new Spitter(a)
  implicit def toSpittee[S](a: ExcitableAnimal[S]) = new Spittee(a)
}
trait Quadruped[SELF] extends ExcitableAnimal[SELF] { self: SELF =>
}
class Dog(anger: Int) extends Quadruped[Dog] {
  def withMoreAnger: Dog = new Dog(anger + 2)
  override def toString = s"${if (anger > 0) "angry" else "mild"} ${if (anger > 2) "hound" else "puppy"}"
}
class Cat(anger: Int) extends Quadruped[Cat] {
  def withMoreAnger: Cat = new Cat(anger + 1)
  override def toString = s"${if (anger > 0) "gnarly" else "sweet"} ${if (anger > 1) "pussy" else "kitteh"}"
}

class Spitter[S](val spitter: Animal[S]) extends AnyVal {
  def spitAt[T](spittee: ExcitableAnimal[T]) = spittee.spatUpon
}
class Spittee[S](val spittee: ExcitableAnimal[S]) extends AnyVal {
  def spatUpon = spittee.withMoreAnger
}
object Test {
  def Dog(anger: Int) = new Dog(anger)
  def Cat(anger: Int) = new Cat(anger)
  def main(args: Array[String]) {
    val dog = Dog(anger = 0)
    val cat = Cat(anger = 0)
    val angryCat: Cat = dog spitAt cat // fine

    val anotherDog = Dog(0)
    val animals = Seq(dog, cat)
    println(animals)
    val angryAnimals = for (a <- animals) yield anotherDog spitAt a
    println(angryAnimals)
    val poAnimals = for (a <- angryAnimals) yield anotherDog spitAt a
    println(poAnimals)
  }
}

供参考,另一个角色:

trait Vermiform[SELF] extends Animal[SELF] { self: SELF =>
  // worm saliva is actually quite pleasant
  def spitAt[A <: SpittableAnimal[A]](a: A): a.SpatAt = a
} // not excitable
case class Worm() extends Vermiform[Worm]

刚才在车上,我发现自己想知道蠕虫唾液是否确实具有镇静作用。

答案 1 :(得分:1)

这是另一种看法。我想这就是“吐痰”。

它只显示类型参数的差异,以及spitAt的修订签名。

它还在Worm中展示了另一个无代表问题的例子,让你创建一个具有抽象类型成员的具体类有什么好处?

package spit

import language.higherKinds

trait Excitable[+SELF] { self: SELF =>
  def withMoreAnger: SELF
}
trait Animal[+SELF] { self: SELF =>
  type SpatAt = SELF // to reveal SELF for method spitAt used as a dependent method type
  type SpittableAnimal[S] <: Animal[S]
  def spitAt[A](a: SpittableAnimal[A]): a.SpatAt
}
trait ExcitableAnimal[+SELF] extends Animal[SELF] with Excitable[SELF] { self: SELF =>
  type SpittableAnimal[S] = ExcitableAnimal[S]
  def spitAt[A](a: SpittableAnimal[A]): a.SpatAt = a.withMoreAnger
}
trait Quadruped[+SELF] extends ExcitableAnimal[SELF] { self: SELF =>
}
case class Dog(anger: Int) extends Quadruped[Dog] {
  def withMoreAnger: Dog = copy(anger = anger + 1)
}
case class Cat(anger: Int) extends Quadruped[Cat] {
  def withMoreAnger: Cat = copy(anger = anger + 1)
}
trait Vermiform[SELF] extends Animal[SELF] { self: SELF =>
  // worm saliva is actually quite pleasant
  def spitAt[A](a: SpittableAnimal[A]): a.SpatAt = a.asInstanceOf[A]
}
case class Worm() extends Vermiform[Worm]

object Test {
  def main(args: Array[String]) {
    val dog = Dog(anger = 0)
    val cat = Cat(anger = 0)
    val angryCat: Cat = dog spitAt cat // fine

    val anotherDog = Dog(0)
    val animals = Seq(dog, cat)
    val angryAnimals = for (a <- animals) yield anotherDog spitAt a
    val podAnimals = for (a <- angryAnimals) yield anotherDog spitAt a
    println(animals)
    println(angryAnimals)
    println(podAnimals)

    val worm = Worm()
    //println(worm spitAt dog) // Worms don't spit
  }
}

答案 2 :(得分:0)

与此同时,我读到并记住了这一句:The Typeclass Pattern - An Alternative to Inheritance
正如user1296806提到here,类型类值得一试。所以这就是:

trait Excitable[T] { // TYPECLASS
  def withMoreAnger(t: T): T
}
trait Animal {
  type SpittableAnimal <: Animal
  def spitAt[A <: SpittableAnimal: Excitable](a: A): A
}
trait ExcitableAnimal extends Animal {
  type SpittableAnimal = ExcitableAnimal
  def spitAt[A <: SpittableAnimal: Excitable](a: A): A = implicitly[Excitable[A]] withMoreAnger a
}

object Dog {
  implicit object ExcitableDog extends Excitable[Dog] {
    def withMoreAnger(dog: Dog): Dog = dog copy (anger = dog.anger + 1)
  }
}
case class Dog(anger: Int) extends Quadruped

object Cat {
  implicit object ExcitableCat extends Excitable[Cat] {
    def withMoreAnger(cat: Cat): Cat = cat copy (anger = cat.anger + 1)
  }
}
case class Cat(anger: Int) extends Quadruped

sealed trait Quadruped extends ExcitableAnimal // sealed: to couple pattern match at implicit object ExcitableQuadruped and all subclasses of Quadruped
object Quadruped {
  implicit object ExcitableQuadruped extends Excitable[Quadruped] {
    def withMoreAnger(quadruped: Quadruped): Quadruped = {
      quadruped match {
        case dog: Dog => implicitly[Excitable[Dog]].withMoreAnger(dog)
        case cat: Cat => implicitly[Excitable[Cat]].withMoreAnger(cat)
      }
    }
  }
}

val dog = Dog(anger = 0)
val cat = Cat(anger = 0)
val angryCat: Cat = dog spitAt cat // fine
val anotherDog = Dog(0)
val animals: Seq[Quadruped] = Seq(dog, cat)
val angryAnimals: Seq[Quadruped] = for (a <- animals) yield anotherDog spitAt a // fine
val podAnimals: Seq[Quadruped] = for (a <- angryAnimals) yield anotherDog spitAt a // fine, still a Seq[Quadruped]