| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Type.Errors
Contents
Synopsis
- data ErrorMessage where
- Text :: forall. Symbol -> ErrorMessage
- ShowType :: forall t. t -> ErrorMessage
- (:<>:) :: forall. ErrorMessage -> ErrorMessage -> ErrorMessage
- (:$$:) :: forall. ErrorMessage -> ErrorMessage -> ErrorMessage
- type family PrettyPrintList (vs :: [k]) :: ErrorMessage where ...
- type family ShowTypeQuoted (t :: k) :: ErrorMessage where ...
- type family TypeError (a :: ErrorMessage) :: b where ...
- type DelayError err = Eval (DelayErrorFcf err)
- data DelayErrorFcf :: ErrorMessage -> Exp k
- type NoError = (() :: Constraint)
- type NoErrorFcf = Pure NoError
- type family IfStuck (expr :: k) (b :: k1) (c :: Exp k1) :: k1 where ...
- type WhenStuck expr b = IfStuck expr b NoErrorFcf
- type UnlessStuck expr c = IfStuck expr NoError c
- type PHANTOM = VAR
- type UnlessPhantom exp err = Eval (UnlessPhantomFcf exp err)
- data UnlessPhantomFcf :: k -> ErrorMessage -> Exp Constraint
- type family Subst (e :: k1) (var :: k2) (sub :: k2) :: k1 where ...
- type VAR = SubMe Var
- type family SubstVar (e :: k1) (r :: k2) :: k1 where ...
- type Exp a = a -> Type
- type family Eval (e :: Exp a) :: a
- data Pure (b :: a) (c :: a) :: forall a. a -> a -> Type
Generating Error Messages
data ErrorMessage where #
A description of a custom type error.
Constructors
| Text :: forall. Symbol -> ErrorMessage | Show the text as is. |
| ShowType :: forall t. t -> ErrorMessage | Pretty print the type.
|
| (:<>:) :: forall. ErrorMessage -> ErrorMessage -> ErrorMessage infixl 6 | Put two pieces of error message next to each other. |
| (:$$:) :: forall. ErrorMessage -> ErrorMessage -> ErrorMessage infixl 5 | Stack two pieces of error message on top of each other. |
type family PrettyPrintList (vs :: [k]) :: ErrorMessage where ... Source #
Pretty print a list.
>>>:show_error PrettyPrintList '[Bool]... ... 'Bool' ...
>>>:show_error PrettyPrintList '[1, 2]... ... '1', and '2' ...
>>>:show_error PrettyPrintList '["hello", "world", "cool"]... ... "hello", "world", and "cool" ...
Since: 0.1.0.0
Equations
| PrettyPrintList '[] = Text "" | |
| PrettyPrintList '[a] = ShowTypeQuoted a | |
| PrettyPrintList '[a, b] = (ShowTypeQuoted a :<>: Text ", and ") :<>: ShowTypeQuoted b | |
| PrettyPrintList (a ': vs) = (ShowTypeQuoted a :<>: Text ", ") :<>: PrettyPrintList vs |
type family ShowTypeQuoted (t :: k) :: ErrorMessage where ... Source #
Like ShowType, but quotes the type if necessary.
>>>:show_error ShowTypeQuoted Int... ... 'Int' ...
>>>:show_error ShowTypeQuoted "symbols aren't quoted"... ... "symbols aren't quoted" ...
Since: 0.1.0.0
Equations
| ShowTypeQuoted (t :: Symbol) = ShowType t | |
| ShowTypeQuoted t = (Text "'" :<>: ShowType t) :<>: Text "'" |
Emitting Error Messages
type family TypeError (a :: ErrorMessage) :: b where ... #
The type-level equivalent of error.
The polymorphic kind of this type allows it to be used in several settings. For instance, it can be used as a constraint, e.g. to provide a better error message for a non-existent instance,
-- in a context
instance TypeError (Text "Cannot Show functions." :$$:
Text "Perhaps there is a missing argument?")
=> Show (a -> b) where
showsPrec = error "unreachable"
It can also be placed on the right-hand side of a type-level function to provide an error for an invalid case,
type family ByteSize x where
ByteSize Word16 = 2
ByteSize Word8 = 1
ByteSize a = TypeError (Text "The type " :<>: ShowType a :<>:
Text " is not exportable.")
Since: base-4.9.0.0
type DelayError err = Eval (DelayErrorFcf err) Source #
Error messages produced via TypeError are often too strict, and will
be emitted sooner than you'd like. The solution is to use DelayError,
which will switch the error messages to being consumed lazily.
>>>:{foo :: TypeError ('Text "Too eager; prevents compilation") => () foo = () :} ... ... Too eager; prevents compilation ...
>>>:{foo :: DelayError ('Text "Lazy; emitted on use") => () foo = () :}
>>>foo... ... Lazy; emitted on use ...
Since: 0.1.0.0
data DelayErrorFcf :: ErrorMessage -> Exp k Source #
Like DelayError, but implemented as a first-class family.
DelayErrorFcf is useful when used as the last argument to IfStuck and
UnlessStuck.
Since: 0.1.0.0
Instances
| type Eval (DelayErrorFcf a2 :: a1 -> Type) Source # | |
Defined in Type.Errors | |
type NoError = (() :: Constraint) Source #
A helper definition that doesn't emit a type error. This is
occassionally useful to leave as the residual constraint in IfStuck when
you only want to observe if an expression isn't stuck.
Since: 0.1.0.0
type NoErrorFcf = Pure NoError Source #
Like NoError, but implemented as a first-class family. NoErrorFcf is
useful when used as the last argument to IfStuck and UnlessStuck.
Since: 0.1.0.0
Observing Stuckness
type family IfStuck (expr :: k) (b :: k1) (c :: Exp k1) :: k1 where ... Source #
leaves IfStuck expr b cb in the residual constraints whenever
expr is stuck, otherwise it Evaluates c.
Often you want to leave a DelayError in b in order to report an error
when expr is stuck.
The c parameter is a first-class family, which allows you to perform
arbitrarily-complicated type-level computations whenever expr isn't stuck.
For example, you might want to produce a typeclass Constraint here.
Alternatively, you can nest calls to IfStuck in order to do subsequent
processing.
This is a generalization of kcsongor's Break
machinery described in
detecting the undetectable.
Since: 0.1.0.0
type WhenStuck expr b = IfStuck expr b NoErrorFcf Source #
Like IfStuck, but specialized to the case when you don't want to do
anything if expr isn't stuck.
>>>:{observe_no_rep :: WhenStuck (Rep t) (DelayError ('Text "No Rep instance for " ':<>: ShowTypeQuoted t)) => t -> () observe_no_rep _ = () :}
>>>observe_no_rep HasNoRep... ... No Rep instance for 'HasNoRep' ...
>>>observe_no_rep True()
Since: 0.1.0.0
type UnlessStuck expr c = IfStuck expr NoError c Source #
Like IfStuck, but leaves no residual constraint when expr is stuck.
This can be used to ensure an expression isn't stuck before analyzing it
further.
See the example under UnlessPhantomFcf for an example of this use-case.
Since: 0.1.0.0
Observing Phantomness
A meta-variable for marking which argument should be a phantom when
working with UnlessPhantom and UnlessPhantomFcf.
PHANTOM is polykinded and can be used in several settings.
See UnlessPhantom for examples.
Since: 0.1.0.0
type UnlessPhantom exp err = Eval (UnlessPhantomFcf exp err) Source #
determines if the type described by UnlessPhantom expr errexpr
is phantom in the variables marked via PHANTOM. If it's not, it produces
the error message err.
For example, consider the definition:
>>>:{data Qux a b = Qux b :}
which is phantom in a:
>>>:eval_error UnlessPhantom (Qux PHANTOM Int) ('Text "Ok")()
but not in b:
>>>:eval_error UnlessPhantom (Qux Int PHANTOM) ('Text "Bad!")... ... Bad! ...
Unfortunately there is no known way to emit an error message if the variable is a phantom.
Since: 0.1.0.0
data UnlessPhantomFcf :: k -> ErrorMessage -> Exp Constraint Source #
Like UnlessPhantom, but implemented as a first-class family. As such,
this allows UnlessPhantomFcf to be chained after IfStuck to only be run
if an expression isn't stuck.
This can be used to avoid emitting false error messages when a type variable isn't phantom, just ambiguous.
>>>:{observe_phantom :: UnlessStuck f (UnlessPhantomFcf (f PHANTOM) ('Text "It's not phantom!")) => f p -> () observe_phantom _ = () :}
>>>observe_phantom Proxy()
>>>observe_phantom (Just 5)... ... It's not phantom! ...
In the next example, we leave observe_phantom unsaturated, and therefore
f isn't yet known. Without guarding the UnlessPhantomFcf behind
UnlessStuck, this would incorrectly produce the message "It's not
phantom!"
>>>observe_phantom... ... No instance for (Show ... ...
Since: 0.1.0.0
Instances
| type Eval (UnlessPhantomFcf exp err :: Constraint -> Type) Source # | |
Defined in Type.Errors type Eval (UnlessPhantomFcf exp err :: Constraint -> Type) = Coercible (SubstVar exp (Stuck :: (Any :: Type))) (SubstVar exp (DelayError err :: (Any :: Type))) | |
Performing Type Substitutions
type family Subst (e :: k1) (var :: k2) (sub :: k2) :: k1 where ... Source #
substitutes all instances of Subst expr a ba for b in expr.
>>>:kind! Subst (Either Int Int) Int Bool... = Either Bool Bool
>>>:kind! Subst (Either Int Bool) Int [Char]... = Either [Char] Bool
>>>:kind! Subst (Either Int Bool) Either (->)... = Int -> Bool
Since: 0.1.0.0
type family SubstVar (e :: k1) (r :: k2) :: k1 where ... Source #
Working With Fcfs
type family Eval (e :: Exp a) :: a #
Expression evaluator.
Instances
| type Eval (Not False) | |
Defined in Fcf.Data.Bool | |
| type Eval (Not True) | |
Defined in Fcf.Data.Bool | |
| type Eval (Constraints (a ': as) :: Constraint -> Type) | |
Defined in Fcf.Utils | |
| type Eval (Constraints ([] :: [Constraint])) | |
Defined in Fcf.Utils | |
| type Eval (Null (a2 ': as) :: Bool -> Type) | |
| type Eval (Null ([] :: [a]) :: Bool -> Type) | |
| type Eval (a <= b :: Bool -> Type) | |
| type Eval (a >= b :: Bool -> Type) | |
| type Eval (a < b :: Bool -> Type) | |
| type Eval (a > b :: Bool -> Type) | |
| type Eval (False || b :: Bool -> Type) | |
| type Eval (True || b :: Bool -> Type) | |
| type Eval (a || False :: Bool -> Type) | |
| type Eval (a || True :: Bool -> Type) | |
| type Eval (False && b :: Bool -> Type) | |
| type Eval (True && b :: Bool -> Type) | |
| type Eval (a && True :: Bool -> Type) | |
| type Eval (a && False :: Bool -> Type) | |
| type Eval (IsNothing (Nothing :: Maybe a) :: Bool -> Type) | |
| type Eval (IsNothing (Just _a) :: Bool -> Type) | |
| type Eval (IsJust (Nothing :: Maybe a) :: Bool -> Type) | |
| type Eval (IsJust (Just _a) :: Bool -> Type) | |
| type Eval (Length (a2 ': as) :: Nat -> Type) | |
| type Eval (Length ([] :: [a]) :: Nat -> Type) | |
Defined in Fcf.Data.List | |
| type Eval (a + b :: Nat -> Type) | |
| type Eval (a - b :: Nat -> Type) | |
| type Eval (a * b :: Nat -> Type) | |
| type Eval (a ^ b :: Nat -> Type) | |
| type Eval (DelayErrorFcf a2 :: a1 -> Type) Source # | |
Defined in Type.Errors | |
| type Eval (Error msg :: a -> Type) | |
| type Eval (TError msg :: a -> Type) | |
| type Eval (Pure x :: a -> Type) | |
Defined in Fcf.Combinators | |
| type Eval (Join e :: a -> Type) | |
| type Eval (IsLeft (Right _a :: Either a b) :: Bool -> Type) | |
| type Eval (IsLeft (Left _a :: Either a b) :: Bool -> Type) | |
| type Eval (IsRight (Right _a :: Either a b) :: Bool -> Type) | |
| type Eval (IsRight (Left _a :: Either a b) :: Bool -> Type) | |
| type Eval (UnlessPhantomFcf exp err :: Constraint -> Type) Source # | |
Defined in Type.Errors type Eval (UnlessPhantomFcf exp err :: Constraint -> Type) = Coercible (SubstVar exp (Stuck :: (Any :: Type))) (SubstVar exp (DelayError err :: (Any :: Type))) | |
| type Eval (Fst ((,) a2 _b) :: a1 -> Type) | |
Defined in Fcf.Data.Common | |
| type Eval (Snd ((,) _a b) :: a1 -> Type) | |
Defined in Fcf.Data.Common | |
| type Eval (FromMaybe _a (Just b) :: a -> Type) | |
Defined in Fcf.Data.Common | |
| type Eval (FromMaybe a2 (Nothing :: Maybe a1) :: a1 -> Type) | |
| type Eval (TyEq a b :: Bool -> Type) | |
| type Eval (UnBool fal tru True :: a -> Type) | |
| type Eval (UnBool fal tru False :: a -> Type) | |
| type Eval (Guarded x ((p := y) ': ys) :: a2 -> Type) | |
| type Eval (Pure1 f x :: a2 -> Type) | |
Defined in Fcf.Combinators | |
| type Eval (k =<< e :: a2 -> Type) | |
| type Eval (f <$> e :: a2 -> Type) | |
Defined in Fcf.Combinators | |
| type Eval (f <*> e :: a2 -> Type) | |
| type Eval (ConstFn a2 _b :: a1 -> Type) | |
Defined in Fcf.Combinators | |
| type Eval (f $ a3 :: a2 -> Type) | |
Defined in Fcf.Combinators | |
| type Eval (Foldr f y (x ': xs) :: a2 -> Type) | |
| type Eval (Foldr f y ([] :: [a1]) :: a2 -> Type) | |
Defined in Fcf.Data.List | |
| type Eval (UnList y f xs :: a2 -> Type) | |
| type Eval (Uncurry f ((,) x y) :: a2 -> Type) | |
| type Eval (UnMaybe y f (Just x) :: a2 -> Type) | |
| type Eval (UnMaybe y f (Nothing :: Maybe a1) :: a2 -> Type) | |
| type Eval (UnEither f g (Right y :: Either a2 b) :: a1 -> Type) | |
| type Eval (UnEither f g (Left x :: Either a2 b) :: a1 -> Type) | |
| type Eval (Pure2 f x y :: a2 -> Type) | |
Defined in Fcf.Combinators | |
| type Eval ((f <=< g) x :: a3 -> Type) | |
| type Eval (LiftM2 f x y :: a3 -> Type) | |
| type Eval (Flip f y x :: a2 -> Type) | |
Defined in Fcf.Combinators | |
| type Eval (Pure3 f x y z :: a2 -> Type) | |
Defined in Fcf.Combinators | |
| type Eval (LiftM3 f x y z :: a4 -> Type) | |
| type Eval (Init (a2 ': (b ': as)) :: Maybe [a1] -> Type) | |
| type Eval (Init (a2 ': ([] :: [a1])) :: Maybe [a1] -> Type) | |
| type Eval (Init ([] :: [a]) :: Maybe [a] -> Type) | |
| type Eval (Tail (_a ': as) :: Maybe [a] -> Type) | |
| type Eval (Tail ([] :: [a]) :: Maybe [a] -> Type) | |
| type Eval (Head (a2 ': _as) :: Maybe a1 -> Type) | |
| type Eval (Head ([] :: [a]) :: Maybe a -> Type) | |
| type Eval (Last (a2 ': (b ': as)) :: Maybe a1 -> Type) | |
| type Eval (Last (a2 ': ([] :: [a1])) :: Maybe a1 -> Type) | |
| type Eval (Last ([] :: [a]) :: Maybe a -> Type) | |
| type Eval (Cons a2 as :: [a1] -> Type) | |
Defined in Fcf.Data.List | |
| type Eval ((x ': xs) ++ ys :: [a] -> Type) | |
| type Eval (([] :: [a]) ++ ys :: [a] -> Type) | |
Defined in Fcf.Data.List | |
| type Eval (Filter p (a2 ': as) :: [a1] -> Type) | |
| type Eval (Filter _p ([] :: [a]) :: [a] -> Type) | |
Defined in Fcf.Data.List | |
| type Eval (FindIndex p (a2 ': as) :: Maybe Nat -> Type) | |
| type Eval (FindIndex _p ([] :: [a]) :: Maybe Nat -> Type) | |
| type Eval (Find p (a2 ': as) :: Maybe a1 -> Type) | |
| type Eval (Find _p ([] :: [a]) :: Maybe a -> Type) | |
| type Eval (SetIndex n a' as :: [k] -> Type) | |
Defined in Fcf.Data.List | |
| type Eval (Map f (a2 ': as) :: [b] -> Type) | |
| type Eval (Map f ([] :: [a]) :: [b] -> Type) | |
Defined in Fcf.Classes | |
| type Eval (Map f (Just a3) :: Maybe a2 -> Type) | |
| type Eval (Map f (Nothing :: Maybe a) :: Maybe b -> Type) | |
| type Eval (ZipWith f (a2 ': as) (b2 ': bs) :: [c] -> Type) | |
| type Eval (ZipWith _f _as ([] :: [b]) :: [c] -> Type) | |
Defined in Fcf.Data.List | |
| type Eval (ZipWith _f ([] :: [a]) _bs :: [c] -> Type) | |
Defined in Fcf.Data.List | |
| type Eval (Unzip as :: ([a], [b]) -> Type) | |
| type Eval (Cons2 ((,) a3 b) ((,) as bs) :: ([a2], [a1]) -> Type) | |
| type Eval (Map f (Right a3 :: Either a2 a1) :: Either a2 b -> Type) | |
| type Eval (Map f (Left x :: Either a2 a1) :: Either a2 b -> Type) | |
| type Eval (Map f ((,) x a2) :: (k2, k1) -> Type) | |
| type Eval ((f *** f') ((,) b2 b'2) :: (k2, k1) -> Type) | |
| type Eval (Bimap f g (Right y :: Either a b1) :: Either a' b2 -> Type) | |
| type Eval (Bimap f g (Left x :: Either a1 b) :: Either a2 b' -> Type) | |
| type Eval (Bimap f g ((,) x y) :: (k2, k1) -> Type) | |
| type Eval (Map f ((,,) x y a2) :: (k2, k3, k1) -> Type) | |
| type Eval (Map f ((,,,) x y z a2) :: (k2, k3, k4, k1) -> Type) | |
| type Eval (Map f ((,,,,) x y z w a2) :: (k2, k3, k4, k5, k1) -> Type) | |