The path to Deriving
#634
gefjon
started this conversation in
Ideas and Proposals
Replies: 1 comment 1 reply
-
I like Having a dynamic system for registering derive expanders seems over engineered for builtin type classes. I think we could just use a case expression. |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
author: phoebe goldman
title: the path to deriving
The recent implementation of
Addressable
serves as a proof-of-conceptfor how we can implement a general
derive
(orderiving
) mechanism,akin to Rust's
#[derive(...)] type ....
annotations and Haskell'sdata ... deriving (...)
definitions.
In this document, my focus is strictly on semantics and implementation,
not on syntax. For illustration purposes, I'll adopt a Coalton-ified
version of Rust's annotations similar to what we use for
repr
(seebelow). Do not treat this as a sytnax proposal; I just think it's an
obvious way to illustrate what I'm talking about.
Semantically, that definition should, in addition to defining the type
Foo
and its constructorsFooA
andFooB
, define instances(Eq Foo)
and(Hash Foo)
. It might be treated as meaning somethinglike:
Note that both of the generated instances do something obvious and
uninteresting, namely, they destructure the type and apply the relevant
method to its members.
As of Coalton commit
2a98108
(2022-06-17), here's how I think wewould implement that behavior in the Coalton compiler:
Add a slot
derived-instances
to thedefstruct type-definition
defined in parse-type-definition.lisp, which holds a list of
"derive specifiers." For a first implementation, these specifiers
might be symbols naming classes, but if we want to support
Haskell's
deriving via
, we might need to suppliment them withadditional info.
Keep a map from "derive specifiers" to "derive expanders," which
are Common Lisp functions from
type-definition
to S-expressions,which should return a
define-instance
form.make-auto-addressable-instance
, defined intoplevel-define-type.lisp, can serve as the prototypical "derive
expander."
"derive expanders" should probably have some interface for
signaling an error.
Should a "derive expander" have access to any other
information? Should it take an
environment
as an additionalargument? I'm inclined to say no, unless someone can point to a
good reason otherwise.
It may one day become useful to allow users to define their own
"derive expanders," ideally as Coalton functions. For now,
I'll concern myself only with built-in expanders.
During
process-parsed-toplevel-type-definition
(defined intoplevel-define-type.lisp), for each "derive specifier" in
(derived-instances parsed-deftype)
, search the expander map for anappropriate expander. If one exists, call it to produce a
define-instance
form, and return a list of deriveddefine-instance
forms.process-parsed-toplevel-type-definition
currently returnseither
nil
or exactly onedefine-instance
form, but it couldeasily be adapted to return a list of zero or more
define-instance
forms.process-toplevel-type-definitions
will then collect all thederived
define-instance
forms, andprocess-coalton-toplevel
willpass them through the compiler pipeline as appropriate. This
infrastructure already exists, except that
process-toplevel-type-definitions
will need to replace itswhen ... push
with anappend
.Note that, unlike
Addressable
, instances derived with an explicitannotation will not necessitate the class being "early;" the class
just needs to be defined before compiling a type definition which
derives an instance on it.
In summary, the nontrivial work remaining is:
derive
mechanism.a procedure for searching the available expanders and invoking the
appropriate one, erroring if none is found or if the invoked
expander fails.
Beta Was this translation helpful? Give feedback.
All reactions