typelevel / cats

Lightweight, modular, and extensible library for functional programming.
https://typelevel.org/cats/
Other
5.21k stars 1.19k forks source link

cats.data.ValidatedNel issue #3345

Open kevingomu opened 4 years ago

kevingomu commented 4 years ago

Hi all,

I am trying to run docker:publishLocal where I am faced with this error:


[error] /path/to/ClassA.scala:60:8: Cannot prove that cats.data.ValidatedNel[String,path.to.classB] <:< G[A].
[error]       .sequence
[error]        ^

Class A resides in project A, and classB is in project B, and they have this kind of structure:

|--projectName
        |-----project A
        |-----project B
|--build.sbt

The build.sbt looks like this:


lazy val projectA =
  project
    .in(file("projectName/projectA"))
    .enablePlugins(JavaAppPackaging, DockerPlugin)
    .dependsOn(ProjectRef(file("."), "projectB"))
    .settings(
        libraryDependencies ++= Seq("org.typelevel" %% "cats-core" % 2.1.0),
        scalacOptions += "-Ypartial-unification"
        ...
    )

lazy val projectB =
  project
    .in(file("projectName/projectB"))
    .dependsOn(ProjectRef(file("."), "anotherProject"))
    ...

I have researched around and I have added stuff like the "-Ypartial-unification", but to no avail:

plugins.sbt has this:

addSbtPlugin("org.lyranthe.sbt" % "partial-unification" % "1.1.2") The method that is throwing the error is:


def apply(v1: (crwm, icrwm)): Boolean = {
    val (_, cri) = v1

    validationCriteria
      .map(_.validate(cri))
      .sequence
      .map(_ => cri)
      .toEither
      .fold(validationErrors => {
        log.warn(s"""
             |CR didn't pass quality check(s):
             |${validationErrors.toList.mkString("\n")}
           """.stripMargin)
        false
      }, _ => true)
  }

Sorry I have to obfuscate the methods. If it is unclear, please let me know and I will provide any info that I could.

I'm running sbt version 1.2.7

Thank you so much.

ybasket commented 4 years ago

@kevingomu I doubt this problem has something to do with your project set up, it rather looks like your types don't work out. Unfortunately, your example code lacks important type information, so it's hard to help you based on this. I recommend extracting a minimal working (=reproducing behavior) example when you ask for help. That can be a little tricky, but often you'll find the fix for your problem while doing that already and if not, people can help you way more concrete.

Taking your example code and some guesses on what types you have there, I get the following snippet working nicely:

// Assuming you have some collection of checks you want to combine
val validationCriteria: List[Int => ValidatedNel[String, Int]] = List(
  i => Validated.condNel(i > 5, i, "Too small")
  // i => ...
)

val cri = 7 // Dummy input

validationCriteria
  .map(_.apply(cri)) // assuming your .validate takes the cri and produces a ValidatedNel
  .sequence // List[ValidatedNel[Error, SomeType]] => ValidatedNel[Error, List[SomeType]], can be combined with the previous .map to .traverse
  .map(_ => cri) // can be written as .as(cri), but seems unused anyway
  .toEither // unnecessary, Validated(Nel) has a .fold
  .fold(_ => false, _ => true) // simplified for readability

Maybe that helps you already. If not, please provide more details. The Gitter channel is btw a place where can get answers more quickly, plenty of helpful folks there. And we even have some docs on this topic: https://typelevel.org/cats/datatypes/validated.html#parallel-validation