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/
Synopsis
- newtype Refined p x = Refined x
- refine :: Predicate p x => x -> Either RefineException (Refined p x)
- refine_ :: forall p x. Predicate p x => x -> Either RefineException 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)
- refineTH :: (Predicate p x, Lift x) => x -> Q (TExp (Refined p x))
- refineTH_ :: forall p x. (Predicate p x, Lift x) => x -> Q (TExp x)
- unrefine :: Refined p x -> x
- class Typeable p => Predicate p x where
- reifyPredicate :: forall p a. Predicate p a => a -> Bool
- data Not p = Not
- data And l r = And
- type (&&) = And
- data Or l r = Or
- type (||) = Or
- data IdPred = IdPred
- data LessThan (n :: Nat) = LessThan
- data GreaterThan (n :: Nat) = GreaterThan
- data From (n :: Nat) = From
- data To (n :: Nat) = To
- data FromTo (mn :: Nat) (mx :: Nat) = FromTo
- data NegativeFromTo (n :: Nat) (m :: Nat) = NegativeFromTo
- data EqualTo (n :: Nat) = EqualTo
- data NotEqualTo (n :: Nat) = NotEqualTo
- data Odd = Odd
- data Even = Even
- data DivisibleBy (n :: Nat) = DivisibleBy
- 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) = SizeLessThan
- data SizeGreaterThan (n :: Nat) = SizeGreaterThan
- data SizeEqualTo (n :: Nat) = SizeEqualTo
- type NonEmpty = SizeGreaterThan 0
- data Ascending = Ascending
- data Descending = 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
- strengthen :: forall p p' x. (Predicate p x, Predicate p' x) => Refined p x -> Either RefineException (Refined (p && p') x)
- strengthenM :: forall p p' x m. (Predicate p x, Predicate p' x, Monad m) => Refined p x -> RefineT m (Refined (p && p') x)
- data RefineException
- displayRefineException :: RefineException -> Doc ann
- data RefineT m a
- runRefineT :: RefineT m a -> m (Either RefineException a)
- exceptRefine :: Monad m => Either RefineException a -> RefineT m 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
- (|>) :: a -> (a -> b) -> b
- (.>) :: (a -> b) -> (b -> c) -> a -> c
- pretty :: Pretty a => a -> Doc ann
Refined
A refinement type, which wraps a value of type x
,
ensuring that it satisfies a type-level predicate p
.
Refined x |
Instances
Foldable (Refined p) Source # | |
Defined in Refined.Internal fold :: Monoid m => Refined p m -> m # foldMap :: Monoid m => (a -> m) -> Refined p a -> m # foldr :: (a -> b -> b) -> b -> Refined p a -> b # foldr' :: (a -> b -> b) -> b -> Refined p a -> b # foldl :: (b -> a -> b) -> b -> Refined p a -> b # foldl' :: (b -> a -> b) -> b -> Refined p a -> b # foldr1 :: (a -> a -> a) -> Refined p a -> a # foldl1 :: (a -> a -> a) -> Refined p a -> a # toList :: Refined p a -> [a] # length :: Refined p a -> Int # elem :: Eq a => a -> Refined p a -> Bool # maximum :: Ord a => Refined p a -> a # minimum :: Ord a => Refined p a -> a # | |
Eq x => Eq (Refined p x) Source # | |
Ord x => Ord (Refined p x) Source # | |
Defined in Refined.Internal | |
(Read x, Predicate p x) => Read (Refined p x) Source # | This instance makes sure to check the refinement. |
Show x => Show (Refined p x) Source # | |
Lift x => Lift (Refined p x) Source # | |
(Arbitrary a, Typeable a, Typeable p, Predicate p a) => Arbitrary (Refined p a) Source # | |
(ToJSON a, Predicate p a) => ToJSON (Refined p a) Source # | |
Defined in Refined.Orphan.Aeson | |
(FromJSON a, Predicate p a) => FromJSON (Refined p a) Source # | |
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.
refine_ :: forall p x. Predicate p x => x -> Either RefineException x Source #
Like refine
, but discards the refinement.
This _can_ be useful when you only need to validate
that some value at runtime satisfies some predicate.
See also reifyPredicate
.
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.
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.
It may be useful to use this function with the `th-lift-instances` package at https://hackage.haskell.org/package/th-lift-instances/
refineTH_ :: forall p x. (Predicate p x, Lift x) => x -> Q (TExp x) Source #
Like refineTH
, but immediately unrefines the value.
This is useful when some value need only be refined
at compile-time.
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.
Instances
reifyPredicate :: forall p a. Predicate p a => a -> Bool Source #
Reify a Predicate
by turning it into a value-level predicate.
Logical predicates
The negation of a predicate.
>>>
isRight (refine @(Not NonEmpty) @[Int] [])
True
>>>
isLeft (refine @(Not NonEmpty) @[Int] [1,2])
True
The conjunction of two predicates.
>>>
isLeft (refine @(And Positive Negative) @Int 3)
True
>>>
isRight (refine @(And Positive Odd) @Int 203)
True
The disjunction of two predicates.
>>>
isRight (refine @(Or Even Odd) @Int 3)
True
>>>
isRight (refine @(Or (LessThan 3) (GreaterThan 3)) @Int 2)
True
Identity predicate
A predicate which is satisfied for all types.
Arguments passed to
in validate
are not evaluated.validate
IdPred
x
>>>
isRight (refine @IdPred @Int undefined)
True
>>>
isLeft (refine @IdPred @Int undefined)
False
Numeric predicates
data LessThan (n :: Nat) Source #
A Predicate
ensuring that the value is less than the
specified type-level number.
>>>
isRight (refine @(LessThan 12) @Int 11)
True
>>>
isLeft (refine @(LessThan 12) @Int 12)
True
data GreaterThan (n :: Nat) Source #
A Predicate
ensuring that the value is greater than the
specified type-level number.
>>>
isRight (refine @(GreaterThan 65) @Int 67)
True
>>>
isLeft (refine @(GreaterThan 65) @Int 65)
True
Instances
Generic (GreaterThan n) Source # | |
Defined in Refined.Internal type Rep (GreaterThan n) :: Type -> Type # from :: GreaterThan n -> Rep (GreaterThan n) x # to :: Rep (GreaterThan n) x -> GreaterThan n # | |
(Ord x, Num x, KnownNat n) => Predicate (GreaterThan n) x Source # | |
Defined in Refined.Internal | |
m <= n => Weaken (GreaterThan n) (From m) Source # | |
Defined in Refined.Internal | |
m <= n => Weaken (GreaterThan n) (GreaterThan m) Source # | |
Defined in Refined.Internal weaken :: Refined (GreaterThan n) x -> Refined (GreaterThan m) x Source # | |
type Rep (GreaterThan n) Source # | |
A Predicate
ensuring that the value is greater than or equal to the
specified type-level number.
>>>
isRight (refine @(From 9) @Int 10)
True
>>>
isRight (refine @(From 10) @Int 10)
True
>>>
isLeft (refine @(From 11) @Int 10)
True
A Predicate
ensuring that the value is less than or equal to the
specified type-level number.
>>>
isRight (refine @(To 23) @Int 17)
True
>>>
isLeft (refine @(To 17) @Int 23)
True
data FromTo (mn :: Nat) (mx :: Nat) Source #
A Predicate
ensuring that the value is within an inclusive range.
>>>
isRight (refine @(FromTo 0 16) @Int 13)
True
>>>
isRight (refine @(FromTo 13 15) @Int 13)
True
>>>
isRight (refine @(FromTo 13 15) @Int 15)
True
>>>
isLeft (refine @(FromTo 13 15) @Int 12)
True
Instances
Generic (FromTo mn mx) Source # | |
(Ord x, Num x, KnownNat mn, KnownNat mx, mn <= mx) => Predicate (FromTo mn mx) x 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 # | |
type Rep (FromTo mn mx) Source # | |
data NegativeFromTo (n :: Nat) (m :: Nat) Source #
A Predicate
ensuring that the value is greater or equal than a negative
number specified as a type-level (positive) number n
and less than a
type-level (positive) number m
.
>>>
isRight (refine @(NegativeFromTo 5 12) @Int (-3))
True
>>>
isLeft (refine @(NegativeFromTo 4 3) @Int (-5))
True
Instances
Generic (NegativeFromTo n m) Source # | |
Defined in Refined.Internal type Rep (NegativeFromTo n m) :: Type -> Type # from :: NegativeFromTo n m -> Rep (NegativeFromTo n m) x # to :: Rep (NegativeFromTo n m) x -> NegativeFromTo n m # | |
(Ord x, Num x, KnownNat n, KnownNat m) => Predicate (NegativeFromTo n m) x Source # | |
Defined in Refined.Internal | |
type Rep (NegativeFromTo n m) Source # | |
data EqualTo (n :: Nat) Source #
A Predicate
ensuring that the value is equal to the specified
type-level number n
.
>>>
isRight (refine @(EqualTo 5) @Int 5)
True
>>>
isLeft (refine @(EqualTo 6) @Int 5)
True
data NotEqualTo (n :: Nat) Source #
A Predicate
ensuring that the value is not equal to the specified
type-level number n
.
>>>
isRight (refine @(NotEqualTo 6) @Int 5)
True
>>>
isLeft (refine @(NotEqualTo 5) @Int 5)
True
Instances
Generic (NotEqualTo n) Source # | |
Defined in Refined.Internal type Rep (NotEqualTo n) :: Type -> Type # from :: NotEqualTo n -> Rep (NotEqualTo n) x # to :: Rep (NotEqualTo n) x -> NotEqualTo n # | |
(Eq x, Num x, KnownNat n) => Predicate (NotEqualTo n) x Source # | |
Defined in Refined.Internal | |
type Rep (NotEqualTo n) Source # | |
A Predicate
ensuring that the value is odd.
>>>
isRight (refine @Odd @Int 33)
True
>>>
isLeft (refine @Odd @Int 32)
True
A Predicate
ensuring that the value is even.
>>>
isRight (refine @Even @Int 32)
True
>>>
isLeft (refine @Even @Int 33)
True
data DivisibleBy (n :: Nat) Source #
A Predicate
ensuring that the value is divisible by n
.
>>>
isRight (refine @(DivisibleBy 3) @Int 12)
True
>>>
isLeft (refine @(DivisibleBy 2) @Int 37)
True
Instances
Generic (DivisibleBy n) Source # | |
Defined in Refined.Internal type Rep (DivisibleBy n) :: Type -> Type # from :: DivisibleBy n -> Rep (DivisibleBy n) x # to :: Rep (DivisibleBy n) x -> DivisibleBy n # | |
(Integral x, KnownNat n) => Predicate (DivisibleBy n) x Source # | |
Defined in Refined.Internal | |
type Rep (DivisibleBy n) Source # | |
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 #
A Predicate
ensuring that the Foldable
has a length
which is less than the specified type-level number.
>>>
isRight (refine @(SizeLessThan 4) @[Int] [1,2,3])
True
>>>
isLeft (refine @(SizeLessThan 5) @[Int] [1,2,3,4,5])
True
Instances
Generic (SizeLessThan n) Source # | |
Defined in Refined.Internal type Rep (SizeLessThan n) :: Type -> Type # from :: SizeLessThan n -> Rep (SizeLessThan n) x # to :: Rep (SizeLessThan n) x -> SizeLessThan n # | |
(Foldable t, KnownNat n) => Predicate (SizeLessThan n) (t a) Source # | |
Defined in Refined.Internal | |
type Rep (SizeLessThan n) Source # | |
data SizeGreaterThan (n :: Nat) Source #
A Predicate
ensuring that the Foldable
has a length
which is greater than the specified type-level number.
>>>
isLeft (refine @(SizeGreaterThan 3) @[Int] [1,2,3])
True
>>>
isRight (refine @(SizeGreaterThan 3) @[Int] [1,2,3,4,5])
True
Instances
Generic (SizeGreaterThan n) Source # | |
Defined in Refined.Internal type Rep (SizeGreaterThan n) :: Type -> Type # from :: SizeGreaterThan n -> Rep (SizeGreaterThan n) x # to :: Rep (SizeGreaterThan n) x -> SizeGreaterThan n # | |
(Foldable t, KnownNat n) => Predicate (SizeGreaterThan n) (t a) Source # | |
Defined in Refined.Internal | |
type Rep (SizeGreaterThan n) Source # | |
data SizeEqualTo (n :: Nat) Source #
A Predicate
ensuring that the Foldable
has a length
which is equal to the specified type-level number.
>>>
isRight (refine @(SizeEqualTo 4) @[Int] [1,2,3,4])
True
>>>
isLeft (refine @(SizeEqualTo 35) @[Int] [1,2,3,4])
True
Instances
Generic (SizeEqualTo n) Source # | |
Defined in Refined.Internal type Rep (SizeEqualTo n) :: Type -> Type # from :: SizeEqualTo n -> Rep (SizeEqualTo n) x # to :: Rep (SizeEqualTo n) x -> SizeEqualTo n # | |
(Foldable t, KnownNat n) => Predicate (SizeEqualTo n) (t a) Source # | |
Defined in Refined.Internal | |
type Rep (SizeEqualTo n) Source # | |
IsList predicates
A Predicate
ensuring that the Foldable
contains elements
in a strictly ascending order.
>>>
isRight (refine @Ascending @[Int] [5, 8, 13, 21, 34])
True
>>>
isLeft (refine @Ascending @[Int] [34, 21, 13, 8, 5])
True
data Descending Source #
A Predicate
ensuring that the Foldable
contains elements
in a strictly descending order.
>>>
isRight (refine @Descending @[Int] [34, 21, 13, 8, 5])
True
>>>
isLeft (refine @Descending @[Int] [5, 8, 13, 21, 34])
True
Instances
Generic Descending Source # | |
Defined in Refined.Internal type Rep Descending :: Type -> Type # from :: Descending -> Rep Descending x # to :: Rep Descending x -> Descending # | |
(Foldable t, Ord a) => Predicate Descending (t a) Source # | |
Defined in Refined.Internal | |
type Rep 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.
Nothing
Instances
n <= m => Weaken (To n) (To m) Source # | |
m <= n => Weaken (From n) (From m) Source # | |
m <= n => Weaken (GreaterThan n) (From m) Source # | |
Defined in Refined.Internal | |
m <= n => Weaken (GreaterThan n) (GreaterThan m) Source # | |
Defined in Refined.Internal weaken :: Refined (GreaterThan n) x -> Refined (GreaterThan m) x 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)
Strengthening
strengthen :: forall p p' x. (Predicate p x, Predicate p' x) => Refined p x -> Either RefineException (Refined (p && p') x) Source #
Strengthen a refinement by composing it with another.
strengthenM :: forall p p' x m. (Predicate p x, Predicate p' x, Monad m) => Refined p x -> RefineT m (Refined (p && p') x) Source #
Strengthen a refinement by composing it with another
inside of the RefineT
monad.
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 |
Instances
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
Instances
MonadTrans RefineT Source # | |
Defined in Refined.Internal | |
Monad m => MonadError RefineException (RefineT m) Source # | |
Defined in Refined.Internal throwError :: RefineException -> RefineT m a # catchError :: RefineT m a -> (RefineException -> RefineT m a) -> RefineT m a # | |
Monad m => Monad (RefineT m) Source # | |
Functor m => Functor (RefineT m) Source # | |
MonadFix m => MonadFix (RefineT m) Source # | |
Defined in Refined.Internal | |
Monad m => Applicative (RefineT m) Source # | |
Generic1 (RefineT m :: Type -> Type) Source # | |
Generic (RefineT m a) Source # | |
type Rep1 (RefineT m :: Type -> Type) Source # | |
Defined in Refined.Internal | |
type Rep (RefineT m a) Source # | |
Defined in Refined.Internal type Rep (RefineT m a) = D1 (MetaData "RefineT" "Refined.Internal" "refined-0.4.4-7xXnhN9HJ7XByi1PQY08Xe" True) (C1 (MetaCons "RefineT" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (ExceptT RefineException m a)))) |
runRefineT :: RefineT m a -> m (Either RefineException a) Source #
The inverse of
.RefineT
exceptRefine :: Monad m => Either RefineException a -> RefineT m a Source #
Constructor for computations in the
movie.
(The inverse of RefineT
runRefineT
).
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.
(.>) :: (a -> b) -> (b -> c) -> a -> c infixl 9 Source #
Helper function, stolen from the flow
package.