简体   繁体   中英

Fold on NonEmptyList

I'm trying out cats library but I have hard time navigating between things I should import and create. My problem is as follows:

sealed trait Checks
case class CheckViolation(id: Long, msg: String) extends Checks
case class ChecksPassed(ids: Seq[Long]) extends Checks

This is my data structures I want to work with. Every violation should be held as object with msg, checks passed can be aggregated to hold only ids.

object BusinessRuleSetValidation extends App {

  type BRValidationResult = Validated[NonEmptyList[CheckViolation], ChecksPassed]

  def run(): BRValidationResult = {

    implicit val monoidChecksPassed = new Monoid[ChecksPassed] {
      override def empty: ChecksPassed = ChecksPassed(Seq())

      override def combine(x: ChecksPassed, y: ChecksPassed): ChecksPassed = ChecksPassed(x.ids ++ y.ids)
    }



    val check1: BRValidationResult = valid(ChecksPassed(2L))
    val check2: BRValidationResult = invalidNel(CheckViolation(1, "This check was violated"))
    val check3: BRValidationResult = invalidNel(CheckViolation(2, "This is a violation"))


    val p = Foldable[NonEmptyList].fold(NonEmptyList(check1, check2, check3))

The last fold leads to an compilation error.

BusinessRuleSetValidation.scala:48: could not find implicit value for parameter A: cats.Monoid[cats.data.Validated[cats.data.OneAnd[com.adform.br.server.model.validation.CheckViolation,[+A]List[A]],com.adform.br.server.model.validation.ChecksPassed]]
[error]     val p = Foldable[NonEmptyList].fold(NonEmptyList(check1, check2, check3))

NonEmptyList should a perfer candidate for folding. Validated combine should also be there. As for my classes, ChechViolation is in NonEmptyList so it does not need a monoid instance. For the ChecksPassed I've created a monoid instance so I don't really get what is missing here.

EDIT

I did not include my imports and they are important here:

import cats._
import cats.data.Validated._
import cats.data.{NonEmptyList, Validated, Xor}
import cats.data.OneAnd.oneAndFoldable
import cats.std.all._
import cats.syntax.apply._
import cats.syntax.order._
import cats.syntax.xor._
import cats.syntax.semigroup._

Ok, I figured it out.

So I leave an answer maybe some one will find it helpful.

There is no possibility to have a Monoid for NonEmptyList. Why? Monoid needs a neutral element, and for list that would be empty, but our list does not allow this.

So I've changed how checks are grouped from NEL to List.

It turned out that I also need to create a Monoid for Validation and it looked like this:

   implicit val brValidationResutlMonoid = new Monoid[BRValidationResult] {
      override def empty: BRValidationResult = valid(ChecksPassed(Seq.empty))

      override def combine(x: BRValidationResult, y: BRValidationResult): BRValidationResult = (x,y) match {
        case (Valid(a),Valid(b)) => valid(ChecksPassed(a.ids ++ b.ids))
        case (Valid(_), k @ Invalid(_)) => k
        case (f @ Invalid(_), Valid(_)) => f
        case (Invalid(l1),Invalid(l2)) => Invalid(l1.combine(l2))
      }
    }

The types if you listen to them carefully guide you well ;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM