Custom Warnings/Errors in Purescript

Saravanan M
4 min readMar 15, 2024

--

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.

Photo by Breana Panaguiton on Unsplash

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 takes Docas 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 = ""
Note the “Int” message

3. QuoteLabel — Double Quoted Message

This is same as plain text, but will surround the message with a double quotation.

“This is deprecated” — doube quoted.

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) = ...
Warning: V1Request is deprecated, use V2Request instead.

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😊.

--

--

Saravanan M

A place where I share my perspective on the tech topics I've read and enjoyed. Sometimes highly opinionated.