【问题标题】:MyType Type MismatchMyType 类型不匹配
【发布时间】:2012-09-13 17:08:25
【问题描述】:

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

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

但是推断的类型参数不符合方法 spitAt 的类型参数边界,这对我来说很清楚,因为 animals 中元素的 SELF 类型参数至少由不符合的 _ &gt;: Cat with Dog &lt;: Quadruped[_] 限定a.SELF, A 在上面的spitAt 甚至A 在下面的spitAt

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

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

【问题讨论】:

    标签: scala types self-type


    【解决方案1】:

    你喜欢痛吗?你! :)

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

    $ 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]
    

    刚才在车上,我发现自己在怀疑蠕虫的唾液是否真的有镇静作用。

    【讨论】:

    • 抱歉,我无法使用 scala 2.9.3 编译您的代码:angryAnimals-line :no type parameters for method spitAt: (spittee: ExcitableAnimal[T])T exist so that it can be applied to arguments (Quadruped[_ &gt;: Cat with Dog &lt;: Quadruped[_ &gt;: Cat with Dog &lt;: ScalaObject] with ScalaObject] with ScalaObject) --- because --- argument expression's type is not compatible with formal parameter type; found : Quadruped[_ &gt;: Cat with Dog &lt;: Quadruped[_ &gt;: Cat with Dog &lt;: ScalaObject] with ScalaObject] with ScalaObject required: ExcitableAnimal[?0T] 给我一些建议?
    【解决方案2】:

    这是另一个镜头。我想这将是“吐槽”。

    它只是显示类型参数的差异,以及 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
      }
    }
    

    【讨论】:

    • 感谢您的方法!一个严重的问题仍然存在:如果插入val hoppingMadAnimals = for (a &lt;- podAnimals) yield anotherDog spitAt ahoppingMadAnimals 的类型是Seq[Any],这不是预期的。所以问题只是从podAnimals推迟到hoppingMadAnimals
    【解决方案3】:

    与此同时,我继续阅读并记住了这一点: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]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-15
      • 1970-01-01
      • 2022-10-05
      • 1970-01-01
      • 1970-01-01
      • 2018-06-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多