Custom Warnings/Errors in Purescript
Have you ever wished for a way to create custom warnings/errors in your code, similar to the ease of using Java’s @Deprecated annotation? In Java, you can quickly raise a deprecated warning for a function just by annotating it with @Deprecated. But what about Purescript? In this article, we’ll explore how, with the help of the Prim.TypeError module, you can easily create custom warnings/errors.
Prim.TypeError
is a builtin module and it provides the capability to create custom warnings/errors on the fly using a type class approach. To create a warning we can use the Warn
type class constraint, to create an error we can use the Fail
type class constraint.
Here’s an overview of how this can be done,
oldFunction :: Warn (Text "This is deprecated") => String
oldFunction = "..."
Now whenever someone uses the oldFunction
the compiler will show a custom warning,
If you wish to escalate this to an error, just replace the Warn
constraint with Fail
constraint.
Docs
- But if you’ve noticed we are just printing plain messages like “This is deprecated.” How can we print more detailed messages that span multiple lines?
- Before getting into creating those well-formatted multi-line messages. Let’s first understand the
Doc
type, the building block for these messages.Fail/Warn
takesDoc
as their arguments to create the corresponding messages.
class Warn (message :: Doc)
class Fail (message :: Doc)
So to create a custom warning/error, you first want to create a Doc
and purescript provides, I would say, three standalone Doc
constructors.
1. Text — Plain Message
Text
is the one we were using above, it just prints the error/warning message in a plain string format.
data Text :: Symbol -> Doc
Note: While the argument passed to Text (or any other constructor in this module) appears similar to a string, they are actually Symbols, which represents strings at the type level.
2. Quote — Type as Message
This is helpful in printing a type(yeah, a purescript type) in the message.
data Text :: Symbol -> Doc
For example,
oldFunction :: Warn (Quote Int) => String
oldFunction = ""
3. QuoteLabel — Double Quoted Message
This is same as plain text, but will surround the message with a double quotation.
Laying out
These Doc
on their own are barely useful, so purescript also provides us with 2 constructors with which we can compose different Doc
to create complex messages.
1. Beside — Horizontal Stacking
Beside
provides a way to compose messages horizontally
data Beside :: Doc -> Doc -> Doc
Let’s say I want to print a warning message like
<Type1> is deprecated, use <Type2> instead
I can make use of Beside
like,
type DeprecatedWarningDoc a b = Beside
(Quote a)
(Beside
(Text " is deprecated, use ")
(Beside (Quote b) (Text " instead."))
)
and I can attach it in a function signature like,
makeApiCall :: Warn (DeprecatedWarningDoc V1Request V2Request)
=> V1Request
-> String
makeApiCall (V1Request r) = ...
2. Above — Vertical Stacking
Above
let us layout the messages vertically. In the above code snippet, when you swap every instance of Beside with Above, it will result in the below message:
Hope you’ve got something useful from this article. Thank you for reading😊.