2012-09-11 3 views
1

J'ai emprunté l'astuce MyType de Landeihere. Mais récemment, j'ai rencontré un problème avec le type de soi. Un exemple montre ce que je veux dire:MyType Type Incompatibilité

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 !!! 

Pour autant que je peux le révéler, le problème semble être que le trait de soulignement dans la méthode spitAt donne un Any pour a.SELF à la fin. Mais comment puis-je faire fonctionner ce code?
J'ai aussi essayé ceci:

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

Mais des arguments de type inférées ne sont pas conformes à la méthode des limites des paramètres de type de spitAt qui est clair pour moi, puisque l'argument de type SELF des éléments animals sont au moins délimité par _ >: Cat with Dog <: Quadruped[_] qui ne sont pas conformes avec a.SELF, A au-dessus dans spitAt ou même A le spitAt ci-dessous:

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

Alors, quelle est la bonne signature du spitAt méthode pour faire fonctionner les lignes for -loop?
Il se peut que des annotations de variance (+SELF) du paramètre SELF soient utiles, mais je ne sais pas comment.

Répondre

0

Pendant ce temps je lis sur et souvenaient celui-ci: The Typeclass Pattern - An Alternative to Inheritance
Et comme mentionné user1296806here, valent classes de types essayer. Alors voilà:

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

Aimez-vous la douleur zee? Le faites vous! :)

Je ne peux pas croire que cette question n'aime pas l'amour.

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

Qui peut résister à la kitteh gnarly?

Upvote moi ou le kitteh se mettre en colère! Très en colère! Parmi les questions à propos de MyType, nous trouvons des gens qui disent simplement utiliser typeclasses. Fais-le.

Facile à accorder qui peut cracher et être craché sur, et facile à lire le code, peut-être.

que je voulais dire pour obtenir intelligent, par exemple, un chat vraiment en colère se transforme en un GhostCat (colère> 9 vies), mais je dois aller à l'école maternelle avec chauffeur ...

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) 
    } 
} 

Pour référence, un autre personnage :

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] 

dans la voiture tout à l'heure, je me suis demandé si la salive du ver a en fait un effet sédatif.

+0

Désolé, mais je ne peux pas compiler votre code à l'aide scala 2.9.3: 'angryAnimals' ligne:' aucun paramètre de type pour la méthode spitAt: (spittee: ExcitableAnimal [T]) T existe pour qu'il puisse être appliqué aux arguments (Quadruped [_>: Cat avec Dog <: Quadruped [_>: Chat avec Dog <: ScalaObject] avec ScalaObject] avec ScalaObject) --- parce que --- le type d'expression de l'argument n'est pas compatible avec le type de paramètre formel; trouvé: Quadrupède [_>: Chat avec chien <: Quadrupède [_>: Chat avec chien <: ScalaObject] avec ScalaObject] avec ScalaObject requis: ExcitableAnimal [? 0T] 'Quelques conseils pour moi? –

1

Voici une autre prise. Je suppose que ce serait la "prise de la broche".

Il montre juste la variance sur le type param, et une signature révisée pour spitAt.

Il montre également un exemple, dans Worm, de cette autre question sans âge, à quoi bon vous laisser créer une classe concrète avec un membre de type abstrait?

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 
    } 
} 
+0

Merci pour cette approche! Un problème sérieux subsiste: Si vous insérez 'val hoppingMadAnimals = pour (a <- podAnimals) donnez un autre fichier spitAt a', le type de' hoppingMadAnimals' est 'Seq [Any]', ce qui n'est pas prévu. Donc, le problème est seulement reporté de 'podAnimals' à' hoppingMadAnimals'. –

Questions connexes