3

How can I accumulate Scalactic's Or using withGood on a Seq[Or]?

So I have something like following code:

val cs: Seq[BigDecimal Or ErrorMessage]

so I need to do something when all values in cs are Good like this

Accumulation.withGood(cs){...}

Any help is appreciated

Wins
  • 3,420
  • 4
  • 36
  • 70

3 Answers3

1

Or, per http://www.scalactic.org/user_guide/OrAndEvery:

object worksheet {
  println("Welcome to the Scala worksheet")   //> Welcome to the Scala worksheet

  import org.scalactic._
  import Accumulation._

  val test1: Seq[Or[Long, Every[ErrorMessage]]] = Seq(
      Good(1L),
      Good(2L),
      Bad(One("An error")),
      Good(4L),
      Bad(One("Another error"))
      )                                       //> test1  : Seq[org.scalactic.Or[Long,org.scalactic.Every[org.scalactic.ErrorMe
                                              //| ssage]]] = List(Good(1), Good(2), Bad(One(An error)), Good(4), Bad(One(Anoth
                                              //| er error)))
  val test2: Seq[Or[Long, Every[ErrorMessage]]] = Seq(
      Good(1L),
      Good(2L),
      Good(3L),
      Good(4L),
      Good(5L)
      )                                       //> test2  : Seq[org.scalactic.Or[Long,org.scalactic.Every[org.scalactic.ErrorMe
                                              //| ssage]]] = List(Good(1), Good(2), Good(3), Good(4), Good(5))

  test1.combined                              //> res0: org.scalactic.Or[Seq[Long],org.scalactic.Every[org.scalactic.ErrorMess
                                              //| age]] = Bad(Many(An error, Another error))

  test2.combined                              //> res1: org.scalactic.Or[Seq[Long],org.scalactic.Every[org.scalactic.ErrorMess
                                              //| age]] = Good(List(1, 2, 3, 4, 5))
}
1

Yes, you are doing it correctly.

withGood method on Accumulation, applies the good values to the given function, here the function which you would provide in {...} and return the result wrapped in a Good else it returns a Bad containing every error ie. a Bad whose Every includes every value that appears in any Bad.

Here is the definition of withGood():

 def withGood[A, B, ERR, RESULT](
        a: A Or Every[ERR],
        b: B Or Every[ERR]
      )(
        fn: (A, B) => RESULT
      ): RESULT Or Every[ERR] = withGoodCurried(a, b)(fn.curried)
Shivangi Gupta
  • 194
  • 1
  • 10
  • I don't think there is `withGood` signature that allows me to pass a `Seq[Or]`. It's always a definite number. – Wins Aug 01 '18 at 06:23
  • If it is a definite number, then how are you going to decide whether it's value is Good or Bad? – Shivangi Gupta Aug 02 '18 at 06:33
  • That's my question in this SO – Wins Aug 02 '18 at 06:35
  • You actually have to wrap the sequence value in Good or Bad, only then you will be able to apply withGood on it, and accordingly it will return the result wrapped in a Good else it returns a Bad containing every error. You will get it if you drill down in the implementation of withGood, you will see it does pattern matching on Good and Bad classes. – Shivangi Gupta Aug 02 '18 at 10:17
  • I don't think you get my question. I'm having a `Seq[Or[_,_]]`, and I need to use `withGood` for every element within the Sequence. The number of elements is known only during runtime, could be 1, could be 10, could be 100 `Or`s. – Wins Aug 02 '18 at 10:19
  • Yes, there is no signature that allows you to pass Seq[Or] to withGood. However, you can do it by using map and pass each element to withGood. Its return type will also be Seq[Or]. map will accept any number of elements that are there in the Seq. – Shivangi Gupta Aug 02 '18 at 11:16
0

Here's one way:

    object worksheet {
      import org.scalactic._

      val test1: Seq[Or[Long, Every[ErrorMessage]]] = Seq(
          Good(1L),
          Good(2L),
          Bad(One("An error")),
          Good(4L),
          Bad(One("Another error"))
          )                                           //> test1  : Seq[org.scalactic.Or[Long,org.scalactic.Every[org.scalactic.ErrorMe
                                                      //| ssage]]] = List(Good(1), Good(2), Bad(One(An error)), Good(4), Bad(One(Anoth
                                                      //| er error)))
      val test2: Seq[Or[Long, Every[ErrorMessage]]] = Seq(
          Good(1L),
          Good(2L),
          Good(3L),
          Good(4L),
          Good(5L)
          )                                           //> test2  : Seq[org.scalactic.Or[Long,org.scalactic.Every[org.scalactic.ErrorMe
                                                      //| ssage]]] = List(Good(1), Good(2), Good(3), Good(4), Good(5))

      test1.foldLeft(Good(Seq()): Or[Seq[Long], Every[ErrorMessage]]) { (x, y) =>
        Accumulation.withGood(x, y) { (x, y) =>
          x :+ y
        }
      }                                               //> res0: org.scalactic.Or[Seq[Long],org.scalactic.Every[org.scalactic.ErrorMess
                                                      //| age]] = Bad(Many(An error, Another error))

      test2.foldLeft(Good(Seq()): Or[Seq[Long], Every[ErrorMessage]]) { (x, y) =>
        Accumulation.withGood(x, y) { (x, y) =>
          x :+ y
        }
      }                                               //> res1: org.scalactic.Or[Seq[Long],org.scalactic.Every[org.scalactic.ErrorMess
                                                      //| age]] = Good(List(1, 2, 3, 4, 5))

    }