# fthomas/refined

Fetching contributors…
Cannot retrieve contributors at this time
106 lines (77 sloc) 4.28 KB

# Custom predicates

The library comes with a lot predefined predicates but also allows to define your own. This example shows how to add predicates for a simple type representing a point in a two-dimensional Cartesian coordinate system. We start by defining a `Point` class that represents a point in our coordinate system:

```scala> case class Point(x: Int, y: Int)
defined class Point```

The axes of a two-dimensional Cartesian coordinate system divide the plane into four infinite regions, called quadrants, which are often numbered 1st to 4th. Suppose we want to refine `Point`s with the quadrant they are lying in. So let's create simple types that represent the four quadrants:

```scala> case class Quadrant1()

We now have type-level predicates and a type that we want to refine with these predicates. The next step is to define instances of the `Validate` type class for `Point` that are indexed by the corresponding quadrant predicate. We use the `Validate.fromPredicate` function to create the instances from two functions, one that checks if a given `Point` lies in the corresponding quadrant and one that provides a string representation for the predicate that is used for error messages:

```import eu.timepit.refined.api.Validate

Validate.fromPredicate(p => p.x >= 0 && p.y >= 0, p => s"(\$p is in quadrant 1)", Quadrant1())

Validate.fromPredicate(p => p.x < 0 && p.y >= 0, p => s"(\$p is in quadrant 2)", Quadrant2())

Validate.fromPredicate(p => p.x < 0 && p.y < 0, p => s"(\$p is in quadrant 3)", Quadrant3())

Validate.fromPredicate(p => p.x >= 0 && p.y < 0, p => s"(\$p is in quadrant 4)", Quadrant4())```

We have now everything in place to refine `Point` values with the `refineV` function and our predicates:

```scala> import eu.timepit.refined.refineV
import eu.timepit.refined.refineV

We can also use refined's higher order predicates, which take other predicates as arguments, with our quadrant predicates (without defining corresponding `Validate` instances):

```scala> import eu.timepit.refined.boolean.Not
import eu.timepit.refined.boolean.Not

res4: Either[String,eu.timepit.refined.api.Refined[Point,eu.timepit.refined.boolean.Not[Quadrant1]]] = Left(Predicate (Point(5,4) is in quadrant 1) did not fail.)

scala> import eu.timepit.refined.boolean.Or
import eu.timepit.refined.boolean.Or