我可以使用类型类来获得子类的非混合、combine 的共享实现以及 return 子类类型吗?
Can I use typeclasses to get non-mixing of subclasses, shared implementation of combine, and also return subclass type?
猫和狗都是宠物,因此有年龄。我想定义一个 chooseOldest
方法,给定两只猫或两只狗,将选择最老的宠物,但当猫 和 时将拒绝选择出现了一只狗。
用 type类 实现的半群似乎让我完成了 90%,但我不知道是否可以定义 chooseOldest
once;理论上,因为所有 Pet
都有一个年龄,所以不需要为每个 Pet
实现它,但实际上我不知道如何只定义一次,同时仍然返回子类化并保留“猫狗不混”规则:
trait Pet {
def age: Int
// When implementation is shared, it *doesn't* return the subclass type
def _chooseOldest(rhs: Pet): Pet = if (age > rhs.age) this else rhs
}
case class Dog(age: Int) extends Pet
case class Cat(age: Int) extends Pet
trait Semigroup[A] {
def chooseOldest(lhs: A, rhs: A): A
}
// When the implementation returns the subclass type, it can't be shared
implicit val dogSemigroup = new Semigroup[Dog] {
override def chooseOldest(lhs: Dog, rhs: Dog): Dog = if (lhs.age > rhs.age) lhs else rhs
}
implicit val catSemigroup = new Semigroup[Cat] {
override def chooseOldest(lhs: Cat, rhs: Cat): Cat = if (lhs.age > rhs.age) lhs else rhs
}
def chooseGeneric[P <: Pet](p1: P, p2: P)(implicit ev: Semigroup[P]): P = ev.chooseOldest(p1, p2)
def canChooseDogs(d1: Dog, d2: Dog)(implicit ev: Semigroup[Dog]): Dog = chooseGeneric(d1, d2)(ev)
def canChooseCats(c1: Cat, c2: Cat)(implicit ev: Semigroup[Cat]): Cat = chooseGeneric(c1, c2)(ev)
// Appropriately errors because there is no Semigroup[Pet]
def cantMixCatsAndDogs(c: Cat, d: Dog)(implicit ev: Semigroup[Pet]): Pet = chooseGeneric(c, d)(ev)
如果我无法解决这个问题,我会尝试 ,但我怀疑这里有一个我缺少的解决方案,因为这是我第一次涉足类型 [=42] =].
是否可以使用 type类 实现 3 个给定的要求?
- 猫狗不能“合体”
chooseOldest
有一个实现
- 存在
chooseOldest
returns 子类类型
你可以这样做:
sealed trait Pet {
def age: Int
}
object Pet {
final case class Dog(age: Int) extends Pet
final case class Cat(age: Int) extends Pet
sealed trait ChooseOldest[P <: Pet] {
def apply(p1: P, p2: P): P
}
object ChooseOldest {
given instance[P <: Pet](using NotGiven[P =:= Pet]): ChooseOldest[P] with
override def apply(p1: P, p2: P): P =
if (p1.age > p2.age) p1 else p2
}
extension [P <: Pet](self: P)(using ev: ChooseOldest[P])
def chooseOldest(other: P): P =
ev(self, other)
}
请注意,NotGiven[P =:= Pet]
确保不会存在允许混合类型的实例。
猫和狗都是宠物,因此有年龄。我想定义一个 chooseOldest
方法,给定两只猫或两只狗,将选择最老的宠物,但当猫 和 时将拒绝选择出现了一只狗。
用 type类 实现的半群似乎让我完成了 90%,但我不知道是否可以定义 chooseOldest
once;理论上,因为所有 Pet
都有一个年龄,所以不需要为每个 Pet
实现它,但实际上我不知道如何只定义一次,同时仍然返回子类化并保留“猫狗不混”规则:
trait Pet {
def age: Int
// When implementation is shared, it *doesn't* return the subclass type
def _chooseOldest(rhs: Pet): Pet = if (age > rhs.age) this else rhs
}
case class Dog(age: Int) extends Pet
case class Cat(age: Int) extends Pet
trait Semigroup[A] {
def chooseOldest(lhs: A, rhs: A): A
}
// When the implementation returns the subclass type, it can't be shared
implicit val dogSemigroup = new Semigroup[Dog] {
override def chooseOldest(lhs: Dog, rhs: Dog): Dog = if (lhs.age > rhs.age) lhs else rhs
}
implicit val catSemigroup = new Semigroup[Cat] {
override def chooseOldest(lhs: Cat, rhs: Cat): Cat = if (lhs.age > rhs.age) lhs else rhs
}
def chooseGeneric[P <: Pet](p1: P, p2: P)(implicit ev: Semigroup[P]): P = ev.chooseOldest(p1, p2)
def canChooseDogs(d1: Dog, d2: Dog)(implicit ev: Semigroup[Dog]): Dog = chooseGeneric(d1, d2)(ev)
def canChooseCats(c1: Cat, c2: Cat)(implicit ev: Semigroup[Cat]): Cat = chooseGeneric(c1, c2)(ev)
// Appropriately errors because there is no Semigroup[Pet]
def cantMixCatsAndDogs(c: Cat, d: Dog)(implicit ev: Semigroup[Pet]): Pet = chooseGeneric(c, d)(ev)
如果我无法解决这个问题,我会尝试
是否可以使用 type类 实现 3 个给定的要求?
- 猫狗不能“合体”
chooseOldest
有一个实现- 存在
chooseOldest
returns 子类类型
你可以这样做:
sealed trait Pet {
def age: Int
}
object Pet {
final case class Dog(age: Int) extends Pet
final case class Cat(age: Int) extends Pet
sealed trait ChooseOldest[P <: Pet] {
def apply(p1: P, p2: P): P
}
object ChooseOldest {
given instance[P <: Pet](using NotGiven[P =:= Pet]): ChooseOldest[P] with
override def apply(p1: P, p2: P): P =
if (p1.age > p2.age) p1 else p2
}
extension [P <: Pet](self: P)(using ev: ChooseOldest[P])
def chooseOldest(other: P): P =
ev(self, other)
}
请注意,NotGiven[P =:= Pet]
确保不会存在允许混合类型的实例。