неоднозначные неявные значения: соответствуют ожидаемому типу cats.derived.MkShow [A]: показать котов: котят - PullRequest
0 голосов
/ 05 января 2019

Я пытаюсь создать Show Instance для своего пользовательского класса Config.

Файл 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] 

Я новичок в функциональном программировании с использованием кошек. Как я могу разрешить это исключение.

1 Ответ

0 голосов
/ 06 января 2019

К сожалению, сообщение об ошибке, когда задействованы такие сложные импликации и макросы, далеко от совершенства. Сообщение, которое вы видите, на самом деле означает, что некоторые требуемые последствия для реального генератора (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.*? Я бы сказал, что в целом размещение вашего пользовательского кода в пакетах сторонней библиотеки - это простой способ испортить ситуацию.

...