不明确的隐式值:匹配预期类型 cats.derived.MkShow[A]:显示 cats:kittens

ambiguous implicit values: match expected type cats.derived.MkShow[A]: show cats:kittens

我正在尝试为我的自定义配置创建显示实例 class。

build.sbt 文件是 -

    name := "circe-demo"

    version := "0.1"

    scalaVersion := "2.11.12"

    resolvers += Resolver.bintrayRepo("ovotech", "maven")

    libraryDependencies += "io.circe" %% "circe-core" % "0.11.0"
    libraryDependencies += "io.circe" %% "circe-parser" % "0.11.0"
    libraryDependencies += "io.circe" %% "circe-generic" % "0.11.0"
    libraryDependencies += "org.typelevel" %% "kittens" % "1.2.0"


    libraryDependencies ++= Seq(
    "is.cir" %% "ciris-cats",
    "is.cir" %% "ciris-cats-effect",
    "is.cir" %% "ciris-core",
    "is.cir" %% "ciris-enumeratum",
    "is.cir" %% "ciris-refined"
    ).map(_ % "0.12.1")

完整代码为-

    import enumeratum.{Enum, EnumEntry}

    sealed abstract class AppEnvironment extends EnumEntry

    object AppEnvironment extends Enum[AppEnvironment] {
    case object Local extends AppEnvironment
    case object Testing extends AppEnvironment
    case object Production extends AppEnvironment

    override val values: Vector[AppEnvironment] =
        findValues.toVector
    }

    import java.net.InetAddress
    import scala.concurrent.duration.Duration

    final case class ApiConfig(host: InetAddress, port: Int, apiKey: String, timeout: Duration)

    import java.net.InetAddress
    import cats.Show
    import cats.derived.semi
    import ciris.config.loader.AppEnvironment.{Local, Production, Testing}
    import enumeratum.EnumEntry
    import eu.timepit.refined.auto._
    import eu.timepit.refined.types.string.NonEmptyString
    import scala.concurrent.duration._

    final case class Config(appName: NonEmptyString, environment: AppEnvironment, api: ApiConfig)

    object Config {
    implicit val showConfig: Show[Config] = {
        implicit val showDuration: Show[Duration] =
        Show.fromToString

        implicit val showInetAddress: Show[InetAddress] =
        Show.fromToString

        implicit def showEnumEntry[E <: EnumEntry]: Show[E] =
        Show.show(_.entryName)

        // Show.show[Config](x => s"api = ${x.api} appName = ${x.appName} environment ${x.environment}")
        semi.show
        }
    }
上面代码中的

semi.show 抛出以下异常 -

    [error] /Users/rajkumar.natarajan/Documents/Coding/kafka_demo/circe-demo/src/main/scala/ciris/config/loader/Config.scala:32:5: ambiguous implicit values:
    [error]  both value emptyProductDerivedShow in trait MkShowDerivation of type => cats.derived.MkShow[shapeless.HNil]
    [error]  and method emptyCoproductDerivedShow in trait MkShowDerivation of type => cats.derived.MkShow[shapeless.CNil]
    [error]  match expected type cats.derived.MkShow[A]
    [error]     show
    [error]     ^
    [error] one error found
    [error] (Compile / compileIncremental) Compilation failed
    [error] 

我是使用猫进行函数式编程的新手。 我该如何解决这个异常。

不幸的是,当涉及到如此复杂的隐式和宏时,错误报告远非完美。您看到的消息实际上意味着尚未找到真正的生成器(在本例中为 MkShow.genericDerivedShowProduct)所需的一些隐含项,并且搜索返回到一些存在歧义的基本内容。缺少的东西大多是非常基本的,例如 Show[Int]Show[String] 的隐式。获得它们的最简单方法是 import cats.implicits._,但这也会带来 catsStdShowForDuration,即 Show[Duration]。但由于它的实现与您的自定义实现完全相同,因此更容易删除您的自定义实现。缺少的另一件事是 Show[NonEmptyString] 并且很容易创建一个

  implicit def showNonEmptyString: Show[NonEmptyString] = Show.show(nes => nes)

总而言之,当我将你的 showConfig 定义为

implicit val showConfig: Show[Config] = {
  import cats.implicits._

  // is already defined in cats.implicits._
  //implicit val showDuration: Show[Duration] = Show.fromToString

  implicit val showInetAddress: Show[InetAddress] = Show.fromToString

  implicit def showEnumEntry[E <: EnumEntry]: Show[E] = Show.show(_.entryName)

  implicit def showNonEmptyString: Show[NonEmptyString] = Show.show(nes => nes)

  // Show.show[Config](x => s"api = ${x.api} appName = ${x.appName} environment ${x.environment}")
  semi.show
}

它为我编译。

P.S。将 AppEnvironment 放在 ciris.* 包下有什么好的理由吗?我想说的是,通常将您的自定义代码放入第 3 方库的包中很容易把事情搞砸。