1

ここでLandeiから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にfora.SELFを生成することであるように思われます。しかし、どうすればこのコードを機能させることができますか?
私もこれを試しました:

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

しかし、推論された型引数は、メソッドspitAtの型パラメーターの境界に準拠していません。これは、上の要素または以下の要素の型引数が、SELF少なくともanimals、に_ >: Cat with Dog <: Quadruped[_]準拠していないため、私には明らかです。a.SELFAspitAtAspitAt

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

では、 -loop行を機能spitAtさせるためのメソッドの正しいシグネチャは何ですか? おそらく、SELFタイプパラメータの分散アノテーション()が役立つかもしれませんが、その方法はわかりません。for
+SELF

4

3 に答える 3

1

あなたはジーの痛みを楽しんでいますか?あなたは!:)

この質問が愛を楽しんでいないとは信じられません。

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

誰が危険なキッテに抵抗することができますか?

私に賛成するか、キッテが怒ります!非常に怒っています!

MyTypeに関する質問の中には、型クラスを使用するだけだと言う人がいます。早くやれよ。

誰が唾を吐いたり吐いたりする可能性があるかを簡単に認めることができ、おそらくコードを読むのも簡単です。

たとえば、私は賢くなるつもりでした。たとえば、本当に怒っている猫はGhostCatに変わります(怒り> 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 に答える
1

これが別の見方です。これが「スピットテイク」だと思います。

これは、タイプparamの差異と、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 に答える
0

その間、私はこれを読み、思い出しました:型クラスパターン-継承の代替
そしてここで言及されたuser1296806として、型クラスは試してみる価値があります。だからここにあります:

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 に答える