首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TypeClass上的摘要

TypeClass上的摘要
EN

Stack Overflow用户
提问于 2012-09-24 18:07:59
回答 2查看 161关注 0票数 1

从一些简单的代码开始:

代码语言:javascript
复制
trait Moveable[A] {
  def move(a: A): A
}
trait Animal {
  def kick[A <: Animal: Moveable](a: A): A = implicitly[Moveable[A]] move a
}
object Cat {
  implicit object CatMoveable extends Moveable[Cat] {
    def move(cat: Cat): Cat = cat copy (pos = cat.pos + 4)
  }
}
case class Cat(pos: Int) extends Animal
case class Dog(pos: Int) extends Animal
val someAnimal: Animal = Dog(0)
val kickedCat: Cat = someAnimal kick Cat(0)
println(kickedCat) // Cat(4)

我决定把QuadrupedBiped动物区分开来:

代码语言:javascript
复制
trait FourFeetMoveable[A] {
  def moveWithFourFeets(a: A): A
}
trait TwoFeetMoveable[A] {
  def moveWithTwoFeets(a: A): A
}
trait Animal {
  def kick[A <: Animal /*: ??? */](a: A): A
}
trait Quadruped extends Animal {
  def kick[A <: Animal: FourFeetMoveable](a: A): A = implicitly[FourFeetMoveable[A]] moveWithFourFeets a
}
trait Biped extends Animal {
  def kick[A <: Animal: TwoFeetMoveable](a: A): A = implicitly[TwoFeetMoveable[A]] moveWithTwoFeets a
}
object Chicken {
  implicit object ChickenTwoFeetMoveable extends TwoFeetMoveable[Chicken] {
    def moveWithTwoFeets(chicken: Chicken): Chicken = chicken copy (pos = chicken.pos + 2)
  }
}
case class Dog(pos: Int) extends Quadruped
case class Chicken(pos: Int) extends Biped
val someAnimal: Animal = Dog(0)
val kickedChicken: Chicken = someAnimal kick Chicken(0)
println(kickedChicken) // Chicken(2)

必须有两个完全不同的类型FourFeetMoveableTwoFeetMoveable,所以我不能用这样的东西来抽象它们:

代码语言:javascript
复制
trait Moveable[A] {
  def move(a: A): A
}

那么,我如何抽象出在特性kick中作为上下文绑定的类型类型(参见???)?

编辑

对不起,我应该把我的例子说得更清楚些。让我们说,被踢的效果可以是一些运动或其他一些行动。我想用一个典型的例子来概括这一效果。在下面的代码中,我展示了我的意思,并使用抽象类型成员KickingEffect对所需的类型进行抽象,正如_所建议的那样:

代码语言:javascript
复制
trait StumbleEffect[A <: Animal] {
  def stumble(a: A): A
}
trait GlideEffect[A <: Animal] {
  def glide(a: A): A
}
trait Animal {
  type KickingEffect[A <: Animal]
  def kick[A <: Animal: KickingEffect](a: A): A
}
trait Biped extends Animal {
  type KickingEffect[A <: Animal] = StumbleEffect[A]
  override def kick[A <: Animal: StumbleEffect](a: A): A = implicitly[StumbleEffect[A]] stumble a
}
trait Quadruped extends Animal {
  type KickingEffect[A <: Animal] = GlideEffect[A]
  override def kick[A <: Animal: GlideEffect](a: A): A = implicitly[GlideEffect[A]] glide a
}
object Dog {
  implicit object DogGlideEffect extends GlideEffect[Dog] {
    def glide(dog: Dog): Dog = dog copy (pos = dog.pos + 4)
  }
}
case class Dog(pos: Int) extends Quadruped
case class Cat(pos: Int) extends Quadruped
case class Chicken(pos: Int) extends Biped

但后来我遇到了另一个问题,当涉及到动物的序列时:

代码语言:javascript
复制
type Beast[A <: Animal, KE[_ <: Animal]] = A { type KickingEffect[X <: Animal] = KE[X] }
val dogBeast: Beast[Dog, GlideEffect] = Dog(0) // fine

type GlideBeasts[A <: Quadruped] = Beast[A, GlideEffect]
val glideBeasts: Seq[GlideBeasts[Quadruped]] = Seq(Dog(0), Cat(0)) // fine

def kickAll[A <: Animal, KE[_ <: Animal], KA <: Animal](kicker: Beast[A, KE])(animals: Seq[KA])(implicit ev: kicker.KickingEffect[KA]): Seq[KA] = {
  for (a <- animals) yield kicker kick a
}
val cat = Cat(0)
val dog = Dog(0)
kickAll(cat)(Seq(dog)) // wrong inferred kinds of type arguments
kickAll[Cat, GlideEffect, Dog](cat)(Seq(dog)) // missing implicit evidence
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-09-24 18:40:12

是像这样吗?

代码语言:javascript
复制
trait Moveable[A] {
  def move(a: A): A
}
trait FourFeetMoveable[A] extends Moveable[A]
trait TwoFeetMoveable[A] extends Moveable[A]

trait Animal {
  type CanKick[A] <: Moveable[A]
  def kick[A <: Animal : CanKick](a: A): A = implicitly[CanKick[A]] move a
}
trait Quadruped extends Animal {
  type CanKick[A] = FourFeetMoveable[A]
}
trait Biped extends Animal {
  type CanKick[A] = TwoFeetMoveable[A]
}

关于您的编辑:我建议您不要进一步尝试使用类型来建模,除非它确实是应用程序中的一个非常关键的点,或者是一个纯粹的思想实验。在类型安全的设计中,您很容易变得过于雄心勃勃,那么设计工作量与应用程序价值之间的比例就会越来越大;我只想放弃一些编译时安全性,转而进行模式匹配和运行时错误。

如果您确实希望遵循类型路径,那么一旦您有了集合,就需要类似HLists这样的东西来保留集合成员的各个类型。

无论如何,您可以使用示例(使用显式类型参数):

代码语言:javascript
复制
def kickAll[A <: Animal, KE[_ <: Animal], KA <: Animal](
   kicker: Beast[A, KE])(animals: Seq[KA])(implicit effect: KE[KA]): Seq[KA] = {
      for (a <- animals) yield kicker kick a
}

val cat = Cat(0)
val dog = Dog(0)
kickAll(cat)(Seq(dog)) // still doesn't figure out the types
kickAll[Cat, GlideEffect, Dog](cat)(Seq(dog)) // ok!

如前所述,当您尝试使用异构列表(例如,要求不同的效果)时,棘手或不可能的部分出现了。您可以不用为序列的元素使用helper类型类,这样就可以在前面的每一项中解析隐式。

票数 2
EN

Stack Overflow用户

发布于 2012-09-25 09:49:16

顺便提一句,我发现在真正需要类型界之前不要引入类型界总是很有用的。您不仅可以安全地进行大量输入(不是双关语),而且还可以打开选项(例如,对于以后的方差注释)。以下是完全足够的:

代码语言:javascript
复制
trait StumbleEffect[A] {
  def stumble(a: A): A
}
trait GlideEffect[A] {
  def glide(a: A): A
}
trait Animal {
  type KickingEffect[A]
  def kick[A : KickingEffect](a: A): A
}
trait Biped extends Animal {
  type KickingEffect[A] = StumbleEffect[A]
  override def kick[A : StumbleEffect](a: A): A = 
    implicitly[StumbleEffect[A]] stumble a
}
trait Quadruped extends Animal {
  type KickingEffect[A] = GlideEffect[A]
  override def kick[A : GlideEffect](a: A): A = implicitly[GlideEffect[A]] glide a
}

等。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12570449

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档