在一个类型类中使用最低的子类型?

我有以下代码。

sealed trait Animal
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal

trait Show[A] {
  def show(a: A): String
}

class Processor[A](a: A) {
  def print(implicit S: Show[A]): Unit = println(S.show(a))
}

implicit val showCat: Show[Cat] = c => s"Cat=${c.name}"
implicit val showDog: Show[Dog] = d => s"Dog=${d.name}"

val garfield = Cat("Garfield")
val odie = Dog("Odie")

val myPets = List(garfield, odie)

for (p <- myPets) {
  val processor = new Processor(p)
  processor.print // THIS FAILS AT THE MOMENT
}

有谁知道有什么好办法可以让这行代码… processor.print 工作?

我可以想到2种解决方案。

  1. 模式匹配 p 在for循环中。
  2. 创建一个 Show[Animal] 并将其与所有子类型进行模式匹配。

但我想知道是否有更好的方法。

先谢谢你

解决方案:

编译错误是

could not find implicit value for parameter S: Show[Product with Animal with java.io.Serializable]

你可以做 Animal 延伸 ProductSerializable

sealed trait Animal extends Product with Serializable

https:/typelevel.orgblog20180509product-with-serializable.html。

同时,也没有定义隐性的 Show[Animal] 手动

implicit val showAnimal: Show[Animal] = {
  case x: Cat => implicitly[Show[Cat]].show(x)
  case x: Dog => implicitly[Show[Dog]].show(x)
  // ...
}

可以推导出 Show 的密封性状(对后代有实例),并带有

def derive[A]: Show[A] = macro impl[A]

def impl[A: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
  import c.universe._
  val typA = weakTypeOf[A]
  val subclasses = typA.typeSymbol.asClass.knownDirectSubclasses
  val cases = subclasses.map{ subclass =>
    cq"x: $subclass => _root_.scala.Predef.implicitly[Show[$subclass]].show(x)"
  }
  q"""
    new Show[$typA] {
      def show(a: $typA): _root_.java.lang.String = a match {
        case ..$cases
      }
    }"""
}

implicit val showAnimal: Show[Animal] = derive[Animal]

无形

implicit val showCnil: Show[CNil] = _.impossible

implicit def showCcons[H, T <: Coproduct](implicit
  hShow: Show[H],
  tShow: Show[T]
): Show[H :+: T] = _.eliminate(hShow.show, tShow.show)
  
implicit def showGen[A, C <: Coproduct](implicit
  gen: Generic.Aux[A, C],
  show: Show[C]
): Show[A] = a => show.show(gen.to(a))

木兰花

object ShowDerivation {
  type Typeclass[T] = Show[T]

  def combine[T](ctx: CaseClass[Show, T]): Show[T] = null

  def dispatch[T](ctx: SealedTrait[Show, T]): Show[T] =
    value => ctx.dispatch(value) { sub =>
      sub.typeclass.show(sub.cast(value))
    }

  implicit def gen[T]: Show[T] = macro Magnolia.gen[T]
}

import ShowDerivation.gen

Scalaz-deriving

@scalaz.annotation.deriving(Show)
sealed trait Animal extends Product with Serializable

object Show {
  implicit val showDeriving: Deriving[Show] = new Decidablez[Show] {
    override def dividez[Z, A <: TList, ShowA <: TList](tcs: Prod[ShowA])(
      g: Z => Prod[A]
    )(implicit
      ev: A PairedWith ShowA
    ): Show[Z] = null

    override def choosez[Z, A <: TList, ShowA <: TList](tcs: Prod[ShowA])(
      g: Z => Cop[A]
    )(implicit
      ev: A PairedWith ShowA
    ): Show[Z] = z => {
      val x = g(z).zip(tcs)
      x.b.value.show(x.a)
    }
  }
}

对于 cats.Show小猫 你可以随便写

implicit val showAnimal: Show[Animal] = cats.derived.semi.show

问题是 garfieldodieList(garfield, odie) 同类 Animal 而不是 CatDog. 如果你不想为父类型定义类型类的实例,你可以使用类似列表的结构保存各个元素的类型。HList garfield :: odie :: HNil.


为了比较在Dotty中派生类型类

如何在dotty宏中访问case类的参数列表?

给TA打赏
共{{data.count}}人
人已打赏
未分类

如何从wikipedia api中获取行和列的表格数据?

2022-9-8 9:21:34

未分类

Jenkins "警告下一代插件 "无法解析Pytest的JUnit xml报告。

2022-9-8 9:32:36

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索