1

我在这里借用了Landei 的 MyType 技巧。但是最近我遇到了 self 类型的问题。一个例子说明了我的意思:

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方法中的下划线最终会产生一个Anyfor a.SELF。但是我怎样才能使这段代码工作呢?
我也试过这个:

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

但是推断的类型参数不符合方法 spitAt 的类型参数边界,这对我来说很清楚,因为SELF元素的类型参数animals至少有边界_ >: Cat with Dog <: Quadruped[_]不符合a.SELF,AspitAt上面甚至AspitAt下面:

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

那么spitAt使for-loop 行工作的方法的正确签名是什么?
也许 SELF 类型参数的方差注释 ( +SELF) 可能会有所帮助,但我不知道如何。

4

3 回答 3

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
  }
}
于 2012-09-13T05:36:15.217 回答
1

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

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

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

谁能抵挡得了粗犷的小猫?

支持我,否则小猫会生气!很生气!

在有关 MyType 的问题中,我们发现有人说只使用类型类。去做就对了。

很容易授予可能吐口水和被吐口水的人,并且可能易于阅读代码。

我本来想变聪明的,比如,一只非常生气的猫变成了一只鬼猫(愤怒> 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]

刚才在车里,我发现自己想知道蠕虫的唾液是否真的有镇静作用。

于 2012-09-13T01:07:21.647 回答
0

与此同时,我继续阅读并记住了这一点:Typeclass Pattern - An Alternative to Inheritance
正如user1296806在这里提到的那样,typeclasses值得一试。所以这里是:

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]
于 2012-09-13T09:08:25.193 回答