-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcats-execise-data-validation3.sc
68 lines (60 loc) · 2.3 KB
/
cats-execise-data-validation3.sc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import $ivy.`org.typelevel::cats-core:2.0.0`
interp.configureCompiler(_.settings.YpartialUnification.value = true)
@
import cats.Semigroup
import cats.data.Validated
import cats.data.Validated._ // for Valid and Invalid
import cats.instances.all._
import cats.syntax.semigroup._
import cats.syntax.apply._ // for mapN
sealed trait Check[E, A] {
import Check._
def and(that: Check[E, A]): Check[E, A] = And(this, that)
def or(that: Check[E, A]): Check[E, A] = Or(this, that)
def apply(a: A)(implicit s: Semigroup[E]): Validated[E, A] = {
this match {
case Pure(func) => func(a)
case And(left, right) => {
// scalaOption:YpartialUnification is necessary
//ref: https://stackoverflow.com/questions/49865936/scala-cats-validated-value-mapn-is-not-a-member-of-validatednel-tuple
(left(a), right(a)).mapN((_, _) => a)
//alternative
// (left(a), right(a)) match {
// case (Valid(_), Valid(_)) => Valid(a)
// case (Valid(_), Invalid(e)) => Invalid(e)
// case (Invalid(e), Valid(_)) => Invalid(e)
// case (Invalid(e1), Invalid(e2)) => Invalid(e1 |+| e2)
// }
}
case Or(left, right) => {
left(a) match {
case Valid(a) => Valid(a)
case Invalid(e1) => right(a) match {
case Valid(_) => Valid(a)
case Invalid(e2) => Invalid(e1 |+| e2)
}
}
}
}
}
}
object Check {
final case class Or[E, A](left: Check[E, A], right: Check[E, A]) extends Check[E, A]
final case class And[E, A](left: Check[E, A], right: Check[E, A]) extends Check[E, A]
final case class Pure[E, A](func: A => Validated[E, A]) extends Check [E, A]
def pure[E, A](func: A => Validated[E, A]): Check[E, A] = Pure(func)
}
val a: Check[List[String], Int] =
Check.pure { v =>
if(v > 2) Valid(v)
else Invalid(List("Must be > 2"))
}
val b: Check[List[String], Int] =
Check.pure { v =>
if(v < -2) Valid(v)
else Invalid(List("Must be < -2"))
}
val check: Check[List[String], Int] =
a and b
println(check(5))
println(check(0))