Safe Haskell | None |
---|---|
Language | Haskell2010 |
In type theory, a refinement type is a type endowed with a predicate which is assumed to hold for any element of the refined type.
This library allows one to capture the idea of a refinement type
using the Refined
type. A Refined
p
x
wraps a value
of type x
, ensuring that it satisfies a type-level predicate p
.
A simple introduction to this library can be found here: http://nikita-volkov.github.io/refined/
- data Refined p x
- refine :: Predicate p x => x -> Either RefineException (Refined p x)
- refineThrow :: (Predicate p x, MonadThrow m) => x -> m (Refined p x)
- refineFail :: (Predicate p x, MonadFail m) => x -> m (Refined p x)
- refineError :: (Predicate p x, MonadError RefineException m) => x -> m (Refined p x)
- unsafeRefine :: Predicate p x => x -> Refined p x
- refineTH :: (Predicate p x, Lift x) => x -> Q (TExp (Refined p x))
- unrefine :: Refined p x -> x
- class Typeable p => Predicate p x where
- data Not p
- data And l r
- type (&&) = And
- data Or l r
- type (||) = Or
- data LessThan (n :: Nat)
- data GreaterThan (n :: Nat)
- data From (n :: Nat)
- data To (n :: Nat)
- data FromTo (mn :: Nat) (mx :: Nat)
- data EqualTo (n :: Nat)
- data NotEqualTo (n :: Nat)
- type Positive = GreaterThan 0
- type NonPositive = To 0
- type Negative = LessThan 0
- type NonNegative = From 0
- type ZeroToOne = FromTo 0 1
- type NonZero = NotEqualTo 0
- data SizeLessThan (n :: Nat)
- data SizeGreaterThan (n :: Nat)
- data SizeEqualTo (n :: Nat)
- type NonEmpty = SizeGreaterThan 0
- data Ascending
- data Descending
- class Weaken from to where
- andLeft :: Refined (And l r) x -> Refined l x
- andRight :: Refined (And l r) x -> Refined r x
- leftOr :: Refined l x -> Refined (Or l r) x
- rightOr :: Refined r x -> Refined (Or l r) x
- data RefineException
- displayRefineException :: RefineException -> Doc ann
- data RefineT m a
- runRefineT :: RefineT m a -> m (Either RefineException a)
- mapRefineT :: (m (Either RefineException a) -> n (Either RefineException b)) -> RefineT m a -> RefineT n b
- type RefineM a = RefineT Identity a
- refineM :: Either RefineException a -> RefineM a
- runRefineM :: RefineM a -> Either RefineException a
- throwRefine :: Monad m => RefineException -> RefineT m a
- catchRefine :: Monad m => RefineT m a -> (RefineException -> RefineT m a) -> RefineT m a
- throwRefineOtherException :: Monad m => TypeRep -> Doc Void -> RefineT m a
Refined
A refinement type, which wraps a value of type x
,
ensuring that it satisfies a type-level predicate p
.
The only ways that this library provides to construct
a value of type Refined
are with the 'refine-' family
of functions, because the use of the newtype constructor
gets around the checking of the predicate. This restriction
on the user makes unrefine
safe.
If you would really like to
construct a Refined
value without checking the predicate,
use unsafeCoerce
.
Creation
refine :: Predicate p x => x -> Either RefineException (Refined p x) Source #
A smart constructor of a Refined
value.
Checks the input value at runtime.
refineThrow :: (Predicate p x, MonadThrow m) => x -> m (Refined p x) Source #
refineError :: (Predicate p x, MonadError RefineException m) => x -> m (Refined p x) Source #
Constructs a Refined
value at run-time,
calling throwError
if the value
does not satisfy the predicate.
unsafeRefine :: Predicate p x => x -> Refined p x Source #
refineTH :: (Predicate p x, Lift x) => x -> Q (TExp (Refined p x)) Source #
Constructs a Refined
value at compile-time using -XTemplateHaskell
.
For example:
>>>
$$(refineTH 23) :: Refined Positive Int
Refined 23
Here's an example of an invalid value:
>>>
$$(refineTH 0) :: Refined Positive Int
<interactive>:6:4: Value is not greater than 0 In the Template Haskell splice $$(refineTH 0) In the expression: $$(refineTH 0) :: Refined Positive Int In an equation for ‘it’: it = $$(refineTH 0) :: Refined Positive Int
If it's not evident, the example above indicates a compile-time failure, which means that the checking was done at compile-time, thus introducing a zero runtime overhead compared to a plain value construction.
Consumption
Predicate
class Typeable p => Predicate p x where Source #
A typeclass which defines a runtime interpretation of
a type-level predicate p
for type x
.
validate :: Monad m => p -> x -> RefineT m () Source #
Check the value x
according to the predicate p
,
producing an error string if the value does not satisfy.
Logical predicates
The negation of a predicate.
The conjunction of two predicates.
The disjunction of two predicates.
Numeric predicates
data LessThan (n :: Nat) Source #
A Predicate
ensuring that the value is less than the
specified type-level number.
data GreaterThan (n :: Nat) Source #
A Predicate
ensuring that the value is greater than the
specified type-level number.
(Ord x, Num x, KnownNat n) => Predicate (GreaterThan n) x Source # | |
(<=) m n => Weaken (GreaterThan n) (From m) Source # | |
(<=) m n => Weaken (GreaterThan n) (GreaterThan m) Source # | |
A Predicate
ensuring that the value is greater than or equal to the
specified type-level number.
A Predicate
ensuring that the value is less than or equal to the
specified type-level number.
data FromTo (mn :: Nat) (mx :: Nat) Source #
A Predicate
ensuring that the value is within an inclusive range.
data EqualTo (n :: Nat) Source #
A Predicate
ensuring that the value is equal to the specified
type-level number n
.
data NotEqualTo (n :: Nat) Source #
A Predicate
ensuring that the value is not equal to the specified
type-level number n
.
type Positive = GreaterThan 0 Source #
A Predicate
ensuring that the value is greater than zero.
type NonPositive = To 0 Source #
A Predicate
ensuring that the value is less than or equal to zero.
type NonNegative = From 0 Source #
A Predicate
ensuring that the value is greater than or equal to zero.
type NonZero = NotEqualTo 0 Source #
A Predicate
ensuring that the value is not equal to zero.
Foldable predicates
data SizeLessThan (n :: Nat) Source #
data SizeGreaterThan (n :: Nat) Source #
data SizeEqualTo (n :: Nat) Source #
IsList predicates
data Descending Source #
Weakening
class Weaken from to where Source #
A typeclass containing "safe" conversions between refined predicates where the target is weaker than the source: that is, all values that satisfy the first predicate will be guarunteed to satisy the second.
Take care: writing an instance declaration for your custom predicates is
the same as an assertion that weaken
is safe to use:
instance Weaken
Pred1 Pred2
For most of the instances, explicit type annotations for the result value's type might be required.
(<=) n m => Weaken (To n) (To m) Source # | |
(<=) m n => Weaken (From n) (From m) Source # | |
(<=) m n => Weaken (GreaterThan n) (From m) Source # | |
(<=) m n => Weaken (GreaterThan n) (GreaterThan m) Source # | |
(<=) n m => Weaken (LessThan n) (To m) Source # | |
(<=) n m => Weaken (LessThan n) (LessThan m) Source # | |
(<=) m q => Weaken (FromTo n m) (To q) Source # | |
(<=) p n => Weaken (FromTo n m) (From p) Source # | |
((<=) p n, (<=) m q) => Weaken (FromTo n m) (FromTo p q) Source # | |
andLeft :: Refined (And l r) x -> Refined l x Source #
This function helps type inference. It is equivalent to the following:
instance Weaken (And l r) l
andRight :: Refined (And l r) x -> Refined r x Source #
This function helps type inference. It is equivalent to the following:
instance Weaken (And l r) r
leftOr :: Refined l x -> Refined (Or l r) x Source #
This function helps type inference. It is equivalent to the following:
instance Weaken l (Or l r)
rightOr :: Refined r x -> Refined (Or l r) x Source #
This function helps type inference. It is equivalent to the following:
instance Weaken r (Or l r)
Error handling
RefineException
data RefineException Source #
An exception encoding the way in which a Predicate
failed.
RefineNotException !TypeRep | A |
RefineAndException !TypeRep !(These RefineException RefineException) | A |
RefineOrException !TypeRep !RefineException !RefineException | A |
RefineOtherException !TypeRep !(Doc Void) | A |
Show RefineException Source # | |
Generic RefineException Source # | |
Exception RefineException Source # | Encode a |
Pretty RefineException Source # | Pretty-print a |
Monad m => MonadError RefineException (RefineT m) Source # | |
type Rep RefineException Source # | |
displayRefineException :: RefineException -> Doc ann Source #
Display a RefineException
as a Doc
ann
RefineT
and RefineM
A monad transformer that adds
s to other monads.RefineException
The
and pure
functions yield computations that produce
the given value, while return
sequences two subcomputations, exiting
on the first >>=
.RefineException
MonadTrans RefineT Source # | |
Monad m => MonadError RefineException (RefineT m) Source # | |
Monad m => Monad (RefineT m) Source # | |
Functor m => Functor (RefineT m) Source # | |
MonadFix m => MonadFix (RefineT m) Source # | |
Monad m => Applicative (RefineT m) Source # | |
Generic1 * (RefineT m) Source # | |
Generic (RefineT m a) Source # | |
type Rep1 * (RefineT m) Source # | |
type Rep (RefineT m a) Source # | |
runRefineT :: RefineT m a -> m (Either RefineException a) Source #
The inverse of
.RefineT
mapRefineT :: (m (Either RefineException a) -> n (Either RefineException b)) -> RefineT m a -> RefineT n b Source #
Map the unwrapped computation using the given function.
runRefineT
(mapRefineT
f m) = f (runRefineT
m)
refineM :: Either RefineException a -> RefineM a Source #
Constructs a computation in the RefineM
monad. (The inverse of
).runRefineM
runRefineM :: RefineM a -> Either RefineException a Source #
Run a monadic action of type
,
yielding an RefineM
a
.Either
RefineException
a
This is just defined as
.runIdentity
.
runRefineT
throwRefine :: Monad m => RefineException -> RefineT m a Source #
One can use
inside of a monadic
context to begin processing a throwRefine
.RefineException
catchRefine :: Monad m => RefineT m a -> (RefineException -> RefineT m a) -> RefineT m a Source #
A handler function to handle previous
s
and return to normal execution. A common idiom is:RefineException
do { action1; action2; action3 } `catchRefine'
handler
where the action functions can call
. Note that
handler and the do-block must have the same return type.throwRefine
throwRefineOtherException Source #
:: Monad m | |
=> TypeRep | The |
-> Doc Void | A |
-> RefineT m a |
A handler for a
.RefineException
throwRefineOtherException
is useful for defining what
behaviour validate
should have in the event of a predicate failure.