I’ve increasingly found myself wanting a compiler supported annotations on declarations. There are a number of ad-hoc mechanism that have specialized syntax which I think could be subsumed by annotations.
Let’s face it,
newtype is a hideous keyword, and it only exists to enable a (guaranteed) compiler optimization. PureScript’s strictness means there’s no runtime distinction between a
data aside from boxing (unlike Haskell, which has subtleties wrt bottom). I would like to see this as an annotation over
deriving newtype. If we add more strategies in the future we need to extend the syntax of the language for each one. I would like deriving strategies to be annotations on instance declarations.
We have the
Deprecated typeclass, but this only works on value declarations. What if we wanted to deprecate data types (perhaps
SProxy in favor of a polykinded
Proxy) or type synonyms (which may no longer be relevant)? I would like to see warnings and deprecations as annotations.
There’s a PR for safe coercions, which requires adding a new declaration type for roles, and their various keywords. I would like to see roles as annotations on data declarations.
We often need to help the compiler along with optimizations if we want them to always fire. Inlining directives can be annotations on declarations.
And I’m sure many more (backend specific configurations?). I think it would be nice to be able to support these in an extensible way that doesn’t require us to extend the syntax of the language with new keywords.
One idea is reusing the type language. We have compiler solved “magic” typeclasses as a way to extend solving, and we could do something similar with annotations. Annotations could be a specific kind with types in
Prim.Annotation. We could support array literals in types:
import Prim.Annotation (Deriving, Newtype, Roles, Nominal, Deprecated) [Newtype, Roles [Nominal], Deprecated] data Foo a = Foo a [Deriving Newtype] instance eqFoo :: Eq (Foo a)
Or perhaps via rows
import Prim.Annotation (Newtype, Nominal, Deprecated) (rep :: Newtype, roles :: [Nominal], warn :: Deprecated) data Foo a = Foo a (deriving :: Newtype) instance eqFoo :: Eq (Foo a)
I’m sure there are other alternatives to this. What do y’all think?