Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Alexandr
    @AlexandrSokolov
    -Ypartial-unification
    Fabio Labella
    @SystemFw
    yeah, it's in the cats docs everywhere, but still people get caught by it. Can't wait for it to be the default
    Alexandr
    @AlexandrSokolov
    I thout it makes sense to use only if I want to use functions, as monads with the cats
    Fabio Labella
    @SystemFw
    no, everytime you have something with two type params
    e.g. Reader
    also, just so you know, Reader is basically a function
    but it will apply also to Either, Validated, and so on
    basically every time you want a G[_, _] to fit into F[_]
    Alexandr
    @AlexandrSokolov
    yes, and I wanted to ask, what are the advantages to use Reader, if I can make a funciton - a monad and return plain function/monad instead of Reader (special Monad)?
    Fabio Labella
    @SystemFw
    you can do either thing, it's fine
    you'll see a more compelling example once you move to the transformer version of Reader, which is called Kleisli
    Alexandr
    @AlexandrSokolov
    Fabio, are there any other arguments for compiler, which it is recommended to use? Additionally to -Ypartial-unification
    Fabio Labella
    @SystemFw
    that one is the only essential one
    I also highly recommend -Ywarn-value-discard especially once (if) you start using fully pure code with IO instead of Future
    Rob has a giant list here https://tpolecat.github.io/2017/04/25/scalac-flags.html , but some of them give you false negatives so I recommend introducing them gradually as you learn more
    I don't use all of those, fwiw
    Alexandr
    @AlexandrSokolov
    ok. Thank you!
    Thank you all, guys, you helped a lot! The first steps are quite complicated. I feel myself like a junior:)
    which IDE do you use for Scala or recommend? I use Intellij IDEA, but sometimes it highlits code with red, althouth it is not an error and compiler compiles it correctly

    for instance

      def nonBlank(name: String)(data: String): FailFast[String] =
        Right(data).ensure(List(s"$name cannot be blank"))(_.nonEmpty)

    the 2nd line is red in my case. It is said that 'Expression of type Either[Any, String] doesn't conform to expected type FunctorTest.this.FailFast[String]'
    Definition of FailFast: type FailFast[A] = Either[List[String], A]

    but Scala compiler does not even warn about it
    Fabio Labella
    @SystemFw
    I use Emacs, which isn't an IDE and that I do not recommend unless you already like it for other reasons
    I think VsCode with Metals is a good middle ground, but tbh for now I'd recommend to stick to what you know even though it's not perfect, you don't want to learn too many things at once
    I heard that people switch off the IntelliJ checker by activating energy save mode
    mmynsted
    @mmynsted
    I must say that the latest Metals on VsCode is nice.
    Alexandr
    @AlexandrSokolov

    I am trying examples, described at https://github.com/underscoreio/scala-with-cats/blob/develop/src/pages/applicatives/validated.md
    Cannot comple readUser function. Here is a list of all imports and readUser itself (all functions are implemented as described in that page):

      import cats.Semigroupal
      import cats.data.Validated
    
      import cats.instances.string._ // for Semigroup
      import cats.instances.vector._ // for Semigroupal
      import cats.instances.list._ // for Semigroupal
    
      import cats.syntax.apply._   // for mapN
      import cats.syntax.validated._ // for valid and invalid
      import cats.syntax.either._ // for catchOnly
    
    case class User(name:String, age:Int)
    
      def readUser(data: FormData): FailSlow[User] =
        (
          readName(data).toValidated,
          readAge(data).toValidated
        ).mapN(User.apply)

    The error I am getting, is related to the line, where mapN is invoked:

    Error:(166, 7) value mapN is not a member of (cats.data.Validated[List[String],String], cats.data.Validated[List[String],Int])
    possible cause: maybe a semicolon is missing before `value mapN'?
        ).mapN(User.apply)
    Error:(166, 17) missing argument list for method apply in object User
    Unapplied methods are only converted to functions when a function type is expected.
    You can make this conversion explicit by writing `apply _` or `apply(_,_)` instead of `apply`.
        ).mapN(User.apply)

    what do I miss?

    The -Ypartial-unification is enabled:)

    Here is a simplified example, which can be copied as it is:

      import cats.syntax.either._ // for ensure and for catchOnly
      import cats.data.Validated
    
      type FailFastList[A] = Either[List[String], A]
      type FailSlow[A] = Validated[List[String], A]
    
      def nonBlank(name: String)(data: String): FailFastList[String] =
        Right(data).ensure(List(s"$name cannot be blank"))(_.nonEmpty)
    
      case class User(name:String, nickname:String)
    
      import cats.instances.list._ // for Semigroupal
      import cats.syntax.either._ // for catchOnly
      import cats.syntax.apply._ // for mapN
      import cats.syntax.validated._ // for valid and invalid
    
      def fromLists(data: Map[String,String]): FailSlow[String] =
        (
          nonBlank("name")(data.get("name").get).toValidated,
          nonBlank("nickname")(data.get("nickname").get).toValidated
        ).mapN(User.apply)

    Same error with mapN

    Alexandr
    @AlexandrSokolov

    One more question, related to fail slow. Here is an example, in which 2 dates are taken from map and validation checks if one dates comes after another. Most methods are copied from Cats with Scala, except the oneDateAfterAnother:

    object DateFailSlow {
    
     import cats.syntax.either._ // for ensure and for catchOnly
     import java.text.{ParseException, SimpleDateFormat}
     import java.util.Date
     import cats.data.Validated
     import cats.Semigroupal
    
     type FailFast[A] = Either[List[String], A]
     type FailSlow[A] = Validated[List[String], A]
    
     def oneDateAfterAnotherFailFast(dateBefore: String, dateAfter: String)
                                    (map: Map[String, String])(format: SimpleDateFormat)
      : FailFast[Boolean]=
      for {
       dateBefore <- readDate(dateBefore)(map)(format)
       dateAfter <- readDate(dateAfter)(map)(format)
      } yield dateAfter.compareTo(dateBefore) > 0
    
     def readDate(name:String)(map: Map[String, String])(format: SimpleDateFormat):FailFast[Date] =
      for {
       value <- readValue(name)(map)
       res <- parseDate(name)(value)(format)
      } yield res
    
     def readValue(name: String)(map: Map[String, String]): FailFast[String] =
      for {
       value <- getValue(name)(map)
       _ <- nonNullable(name)(value)
       res <- nonBlank(name)(value)
      } yield res
    
     def getValue(name: String)(map: Map[String, String]): FailFast[String] =
      map.get(name)
        .toRight(List(s"$name field not specified"))
    
     def nonNullable(name: String)(data: String): FailFast[String] =
      Right(data).ensure(List(s"$name cannot be nullable"))(_ != null)
    
     def nonBlank(name: String)(data: String): FailFast[String] =
      Right(data).ensure(List(s"$name cannot be blank"))(_.nonEmpty)
    
     def parseDate(name: String)(data: String)(format: SimpleDateFormat): FailFast[Date] =
      Either.catchOnly[ParseException](format.parse(data)).
        leftMap(_ => List(s"$name must be a date"))
    
    }

    It works fine, but I want to accumulate error s in oneDateAfterAnother. And it is an issue for me. Here is my try:

     def oneDateAfterAnotherFailSlow(dateBefore: String, dateAfter: String)
                                    (map: Map[String, String])(format: SimpleDateFormat)
      : FailSlow[Boolean]=
      Semigroupal.map2(
       readDate(dateBefore)(map)(format).toValidated,
       readDate(dateAfter)(map)(format).toValidated
      )(_.compareTo(_) > 0)

    As I understand map2 accepts 2 contexts, in my case it is to Validated and a function, that converts 2 arguments into the 3rd. Boolean in my case. But I am getting the error:

    Error:(23, 4) type mismatch;
     found   : cats.data.Validated[List[String],java.util.Date]
     required: ?F[?A0]
    Note that implicit conversions are not applicable because they are ambiguous:
     both method ArrowAssoc in object Predef of type [A](self: A)ArrowAssoc[A]
     and method Ensuring in object Predef of type [A](self: A)Ensuring[A]
     are possible conversion functions from cats.data.Validated[List[String],java.util.Date] to ?F[?A0]
      )(_.compareTo(_) > 0)

    Can you please explain, what I am doing wrong?

    Noel Welsh
    @noelwelsh
    There is an error here:
    def fromLists(data: Map[String,String]): FailSlow[String]
    The return type is not String but User
    Should be
    def fromLists(data: Map[String,String]): FailSlow[User]
    BTW, there is some new stuff that isn't in the book that might be useful to you: https://typelevel.org/cats/typeclasses/parallel.html
    Alexandr
    @AlexandrSokolov
    @noelwelsh , I have changed a return type to FailSlow[User], the error is slightly changed, but still the root cause is the same
    Alexandr
    @AlexandrSokolov
    Sorry guys, it is definitely my fault. Intellij IDEA is a piece of ... of not a code software for Scala. It turned out, that it does not inhrerit configuration of scala compiler from maven pom.xml, but it must.
    I had to explicitly configure Scala Compler in GUI with '-Ypartial-unification' property. And it seems it fixed the error. Still working on it. But please ignore all my previous questions
    starting working on Scala: first question must be - what is used to build it, maven, sbt or IDE
    Fabio Labella
    @SystemFw

    @AlexandrSokolov as a trick, every time you see:

    required: ?F[?A0]

    with those question marks, it's partial unification

    Alexandr
    @AlexandrSokolov
    Fabio, can we request for such compiler errors a description in the error: 'check if partial unification is enabled'. It will help a lot to analyze and not to guess
    Fabio Labella
    @SystemFw
    well, in 2.13 this error won't happen again so...
    mmynsted
    @mmynsted
    @AlexandrSokolov How often do you find that you must not have partial unification enabled?
    Seems like a reasonable default for most new code.
    Noel Welsh
    @noelwelsh
    Well, glad you got it working.
    Alexandr
    @AlexandrSokolov

    Hi guys!
    I am still playing with validations. A couple of questions. Is there a key difference between using Semigroupal.product and Semigroupal.tuple2. In the first case it is trait, in the 2nd it is object.

    import cats.Semigroupal
    import cats.data.Validated
    import cats.data.Validated.Invalid
    import cats.instances.list._ // for Monoid
    
      type AllErrorsOr[A] = Validated[List[String], A]
      def bothInvalid = {
        Semigroupal[AllErrorsOr].product(
          Validated.invalid(List("Error 1")),
          Validated.invalid(List("Error 2"))
        )
      }
    
      def bothInvalidTuple = {
        Semigroupal.tuple2(
          Validated.invalid(List("Error 1")),
          Validated.invalid(List("Error 2"))
        )
      }
    
      def bothValid = {
        Semigroupal[AllErrorsOr].product(
          Validated.valid(10),
          Validated.valid(20)
        )
      }
    
      def bothValidTuple = {
        Semigroupal.tuple2(
          Validated.valid(10),
          Validated.valid(20)
        )
      }

    With invalids both bothInvalid and bothInvalidTuple give the same result. With valid values, only the first one is compiled. The error I am getting:

    Error:(40, 23) could not find implicit value for parameter semigroupal: cats.Semigroupal[[+A]cats.data.Validated[Nothing,A]]
        Semigroupal.tuple2(

    As I understand it now: In order to use Semigroupal.product, I neen an instance of Validated, which I get through:

    import cats.data.Validated
    import cats.data.Validated.Invalid

    with Semigroupal.tupleN I need in the scope to have an implicit instance of Validated??? But it seems I already have it with the previous imports, right? What do I miss?

    Alexandr
    @AlexandrSokolov

    Exactly this issue is described in the Scala with Cats book, p. 155:

    Validated accumulates errors using a Semigroup , so we need one of those in scope to summon the Semigroupal . If no Semigroup is visible at the call site, we get an annoyingly unhelpful compila on error:

    But I do not get it, where can I find Semigroup for positive Validated, if not in cats.data.Validated

    Noel Welsh
    @noelwelsh
    You need a Semigroup instance for the type that holds the errors. E.g. in your case you need the Semigroup for List.
    Alexandr
    @AlexandrSokolov
    @noelwelsh , it is already in the scope: import cats.instances.list._ // for Monoid
    Alexandr
    @AlexandrSokolov
    I think an issue here, that according to the error, it searchs for Monoid for Nothing:
    cats.Semigroupal[[+A]cats.data.Validated[Nothing,A]]
    And I must somehow say, that actual type is AllErrorsOr
    Validated[List[String], A], but not cats.data.Validated[Nothing,A]]
    Alexandr
    @AlexandrSokolov

    @noelwelsh , one more question, I am looking at example from the book:

    case class User(name: String, age: Int)
    def readName(data: FormData): FailFast[String]...
    def readAge(data: FormData): FailFast[Int] ...
    ...
    def readUser(data: FormData): FailSlow[User] =
    (
      readName(data).toValidated,
      readAge(data).toValidated
    ).mapN(User.apply)

    Let's assume I have another function for validation, that accepts name and age, validated by readName and readAge. For intstance:
    def validBoth(name:String, age:Int):FailFast[Tuple2[String,Int]]

    How to compose these functions together? I cannot use mapN, cause it require function, that does return raw value (not the context, in out case, not Validated). At least it did not work.
    With fail fast it is quite simple, cause I use for-comrehension and have access to the results of readName and readAge:

    for {
      n <- readName...
      i <-  readAge...
      t <- validBoth(n,i)
    } yield t

    but how to get the same result for failslow? Cause in this context it makes much more sense. validBoth - returns FailFast, but the whole composition should be failSlow

    Alexandr
    @AlexandrSokolov
    I need something like flatMap2, then I can write:
    flatMap2(readName(), readAge())(validBoth(_,_))
    But where can I get it?:) Or I am moving in the wrong direction?
    Noel Welsh
    @noelwelsh
    This message was deleted