This module provides type-level functions and operators to make the job of
writing text of custom type errors easier. The motivation behind using custom
type errors is described in detail in the following blog post:
If you want to write the text of a custom error message, you need to use
constructors of the ErrorMessage data type. But this gets messy and
inconvenient pretty quickly. Consider the following examples:
Using combinators from this library, you can define error messages in a simpler
way:
type MessageText (e1 :: k) (e2 :: k) (es :: [k])
= "You require the following two effects from your computation:"
% ""
% " '" <> e1 <> "' and '" <> e2 <> "'"
% ""
% "However, your monad is capable of performing only the following effects:"
% ""
% " " <> es
If you prefer, you can use unicode operators to contstruct messages:
type MessageText (e1 :: k) (e2 :: k) (es :: [k])
= "You require the following two effects from your computation:"
• ""
• " '" ⊕ e1 ⊕ "' and '" ⊕ e2 ⊕ "'"
• ""
• "However, your monad is capable of performing only the following effects:"
• ""
• " " ⊕ es
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.")