-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcats-execise-data-validation4.sc
66 lines (59 loc) · 2.68 KB
/
cats-execise-data-validation4.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
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 Predicate[E, A] {
import Predicate._
def and(that: Predicate[E, A]): Predicate[E, A] =
And(this, that)
def or(that: Predicate[E, A]): Predicate[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) =>
(left(a), right(a)).mapN((_, _) => a)
case Or(left, right) =>
left(a) match {
case Valid(_) => Valid(a)
case Invalid(e1) => right(a) match {
case Valid(_) => Valid(a)
case Invalid(e2) => Invalid(e1 |+| e2)
}
}
}
}
sealed trait Check[E, A, B] {
import Check._
def apply(a: A)(implicit s: Semigroup[E]): Validated[E, B]
def map[C](func: B => C): Check[E, A, C] = Map[E, A, B, C](this, func)
def flatMap[C](func: B => Check[E, A, C]): Check[E, A, C] = FlatMap[E, A, B, C](this, func)
def andThen[C](that: Check[E, B, C]): Check[E, A, C] = AndThen[E, A, B, C](this, that)
}
object Predicate {
final case class And[E, A](left: Predicate[E, A], right: Predicate[E, A]) extends Predicate[E, A]
final case class Or[E, A](left: Predicate[E, A], right: Predicate[E, A]) extends Predicate[E, A]
final case class Pure[E, A](func: A => Validated[E, A]) extends Predicate[E, A]
}
object Check {
final case class Map[E, A, B, C](check: Check[E, A, B], func: B => C) extends Check[E, A, C] {
def apply(a: A)(implicit s: Semigroup[E]):Validated[E, C] = check(a).map(func)
}
final case class Pure[E, A](pred: Predicate[E, A]) extends Check[E, A, A] {
def apply(a: A)(implicit s: Semigroup[E]): Validated[E, A] = pred(a)
}
final case class FlatMap[E, A, B, C](check: Check[E, A, B], func: B => Check[E, A, C]) extends Check[E, A, C] {
def apply(a: A)(implicit s: Semigroup[E]): Validated[E, C] = check(a).withEither(_.flatMap(b => func(b)(a).toEither))
}
final case class AndThen[E, A, B, C](check: Check[E, A, B], that: Check[E, B, C]) extends Check[E, A, C] {
def apply(a: A)(implicit s: Semigroup[E]): Validated[E, C] =check(a).withEither(_.flatMap(b => that(b).toEither))
//check(a).flatMap(b => that(b))
}
def apply[E, A](pred: Predicate[E, A]): Check[E, A, A] = Pure(pred)
}