简体   繁体   中英

How to create semigroup for Boolean when using scalaz?

I am using scalaz for some validation, and somewhere in code there are boolean conditions. A sample is shown below:

import scalaz._, std.AllInstances._

object Temporary {

  def validate(x: Int): scalaz.Validation[List[String], Boolean] = {
    try {
      if (x < 10) {
        scalaz.Success(true)
      } else {
        throw new RuntimeException("why oh why")
      }
    } catch {
      case e: Throwable => scalaz.Failure(List(e.getMessage))
    }
  }


  def main(args: Array[String]) {
    val x = validate(1) +++ validate(10)
    println(x)

    val y = List(1,2,4,10).map(validate(_)).reduce(_ +++ _)
    println(y)
  }

}

I am getting following compilation errors.

Error:(21, 25) could not find implicit value for parameter M1: scalaz.Semigroup[Boolean]
    val x = validate(1) +++ validate(10)
                        ^

I cant figure out how to fix this error. Any pointers?

EDIT

Thanks to the answer from @Travis Brown, here is what fixed it for this example. I added these two lines within the object

  import scalaz.Semigroup, scalaz.std.anyVal.booleanInstance.conjunction
  implicit val booleanSemigroup: Semigroup[Boolean] = conjunction

And now it gives correct validations:

Failure(List(why oh why))
Failure(List(why oh why))

So cool!

There's arguably not a unique semigroup for booleans—both conjunction and disjunction are candidates for the append operation—so Scalaz doesn't provide a Semigroup[Boolean] . It does provide Conjunction and Disjunction tags, and if you add the tag to the static type of your Boolean values (which has no runtime overhead), you can get an instance for the specified operation:

import scalaz.{ @@, Validation }
import scalaz.Tags.Conjunction

object Temporary {

  def validate(x: Int): Validation[List[String], Boolean @@ Conjunction] = {
    try {
      if (x < 10) {
        scalaz.Success(Conjunction(true))
      } else {
        throw new RuntimeException("why oh why")
      }
    } catch {
      case e: Throwable => scalaz.Failure(List(e.getMessage))
    }
  }

  def main(args: Array[String]) {
    val x = validate(1) +++ validate(10)
    println(x)

    val y = List(1,2,4,10).map(validate(_)).reduce(_ +++ _)
    println(y)
  }
}

If you really, really wanted to pick one of these operations as the semigroup operation for booleans, you could do something like this:

import scalaz.Semigroup, scalaz.std.anyVal.booleanInstance.conjunction

implicit val booleanSemigroup: Semigroup[Boolean] = conjunction

And then:

scala> import scalaz.syntax.semigroup._
import scalaz.syntax.semigroup._

scala> true |+| false
res1: Boolean = false

This is somewhat at odds with the Scalaz philosophy, though.

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