This is a port of the refined
Haskell library to Scala.
The linked websites provides an excellent motivation why this kind of library
is useful.
This library consists of:
-
Type-level predicates for refining other types, like
UpperCase
,Positive
,Greater[_0] And LessEqual[_2]
, orLength[Greater[_5]]
. There are also higher order predicates for combining proper predicates likeAnd[_, _]
,Or[_, _]
,Not[_]
,Forall[_]
, orSize[_]
. -
A
Predicate
type class that is able to validate a concrete data type (likeDouble
) against a type-level predicate (likePositive
). -
Two functions
refine
andrefineLit
that take a predicateP
and some value of typeT
, validates this value with aPredicate[P, T]
and returns the value with typeT @@ P
if validation was successful or an error otherwise. (@@
is shapeless' type for tagging types :-))
scala> refine[Positive, Int](5)
res0: Either[String, Int @@ Positive] = Right(5)
scala> refine[Positive, Int](-5)
res1: Either[String, Int @@ Positive] = Left(Predicate failed: (-5 > 0).)
scala> refineLit[NonEmpty, String]("Hello")
res2: String @@ NonEmpty = Hello
scala> refineLit[NonEmpty, String]("")
<console>:27: error: Predicate isEmpty() did not fail.
refineLit[NonEmpty, String]("")
^
scala> type ZeroToOne = Not[Less[_0]] And Not[Greater[_1]]
defined type alias ZeroToOne
scala> refineLit[ZeroToOne, Double](1.8)
<console>:27: error: Right predicate of (!(1.8 < 0) && !(1.8 > 1)) failed: Predicate (1.8 > 1) did not fail.
refineLit[ZeroToOne, Double](1.8)
^
scala> refineLit[AnyOf[Digit :: Letter :: Whitespace :: HNil], Char]('F')
res3: Char @@ AnyOf[Digit :: Letter :: Whitespace :: HNil] = F
Note that refineLit
(which only supports literals) is implemented as macro
and checks at compile time if the given literal conforms to the predicate.
The latest version of the library is 0.0.1, which is built against Scala 2.11.
If you're using SBT, add the following to your build file:
libraryDependencies += "eu.timepit" %% "refined" % "0.0.1"
Instructions for Maven and other build tools is available at search.maven.org.
API documentation of the latest release is available at: http://fthomas.github.io/refined/latest/api/
The library comes with these predefined predicates:
True
: constant predicate that is alwaystrue
False
: constant predicate that is alwaysfalse
Not[P]
: negation of the predicateP
And[A, B]
: conjunction of the predicatesA
andB
Or[A, B]
: disjunction of the predicatesA
andB
AllOf[PS]
: conjunction of all predicates inPS
AnyOf[PS]
: disjunction of all predicates inPS
Digit
: checks if aChar
is a digitLetter
: checks if aChar
is a letterLowerCase
: checks if aChar
is a lower case characterUpperCase
: checks if aChar
is an upper case characterWhitespace
: checks if aChar
is white space
Count[PA, PC]
: counts the number of elements in aTraversableOnce
which satisfy the predicatePA
and passes the result to the predicatePC
Empty
: checks if aTraversableOnce
is emptyNonEmpty
: checks if aTraversableOnce
is not emptyForall[P]
: checks if the predicateP
holds for all elements of aTraversableOnce
Exists[P]
: checks if the predicateP
holds for some of the elements of aTraversableOnce
Size[P]
: checks if the size of aTraversableOnce
satisfies the predicateP
MinSize[N]
: checks if the size of aTraversableOnce
is greater than or equal toN
MaxSize[N]
: checks if the size of aTraversableOnce
is less than or equal toN
Less[N]
: checks if a numeric value is less thanN
LessEqual[N]
: checks if a numeric value is less than or equal toN
Greater[N]
: checks if a numeric value is greater thanN
GreaterEqual[N]
: checks if a numeric value is greater than or equal toN
Equal[N]
: checks if an integral value is equal toN
Positive
: checks if a numeric value is greater than 0Negative
: checks if a numeric value is less than 0Interval[L, H]
: checks if a numeric value is in the interval [L
,H
]
This library is heavily inspired by the refined
library for
Haskell. It even stole its name! Another Scala library that provides type-level
validations is bond
.
refined
is licensed under the MIT license, available at http://opensource.org/licenses/MIT
and also in the LICENSE file.