Repository navigation
Replies: 4 comments 8 replies
|
Really like this proposal! Transformations on generic circuits which may act on varying numbers of registers will be very important |
|
Dependent types!! Like the idea that all guppy types could be python exprs. Less sure how happy the parser would be with this...would that work?? We already have many situations where guppy compilation could fail because of what the python did so I guess that's not new. This does make the language less modular: a bit like C++ template expansion, type-checking can fail somewhat-unexpectedly if you instantiate with an argument that doesn't quite behave the way that was expected, and it's hard to offer any static guarantees about this; you just have to run the python. (Contrast with say Rust parametric polymorphism, instantiation always succeeds, for any type argument satisfying the constraints/bound on the type parameter decl). So I think that's a drawback, that this proposal doubles down on, rather than trying to reduce/minimize/move away from. |
|
We should be very wary of python functions that access (mutable) global variables - whether they mutate, or just read variables mutated elsewhere. This is python....so we probably just have to strongly discourage this...and be very careful about when (and in what order) these functions are called - specifically, how many times (cache after first call?), and what about monomorphization? Or does polymorphism disappear and instead we write python functions that take a type and define a monomorphized guppy function? |
So if you want to do that, can you can get round this deliberate limitation via a much more awkward route of defining a python function, taking type/etc. args, that inspects the type parameters as you suggest ( I mean, if this is an artificial restriction and there is a workaround, then fine, we can see how often the workaround is used. (But it does seem like a two-level system: types are second class citizens alongside first-class nats). |
Uh oh!
There was an error while loading. Please reload this page.
The Problem
Guppy offers powerful metaprogramming capabilities within function bodies via the comptime feature. However, the signature of those functions is static and cannot be set programmatically (except for basic things like array lengths that can be set using comptime expressions). This can be quite limiting: For example, we might want to write a library function that takes an generic number of qubit registers, each with a generic size. This cannot be expressed at the moment.
Proposal
Comptime types
Using the current syntax, we should allow type-level
comptimeexpressions that evaluate to types (instead of just values). In particular, this will require a Python runtime representation of Guppy types:Generic Programming & Monomorphisation
To allow generic programming, these type-level comptime expressions must have access to the generic parameters of the function as python values:
For this to work, we have to monomorphise these generic value parameters during type checking and each version needs to be type-checked separately.
To maintain a bit of parametricity, we should prohibit inspection of type parameters for now, so those will not need to be monomorphised:
Example
The example mentioned in the introduction involving a generic number of qubit registers, each with a generic size would look as follows:
Note that
exampleis a comptime function, otherwiseregisterswould be barely usable since tuple indexing must be static. With inlinecomptimesections, this could be localised further.Variadic functions
Using the syntax so far, the total number of parameters is still fixed (that's why we had to use tuples in the example above). This could be fixed using Python's
*argssyntax:The
*typesyntax was introduced in Python 3.11. The backwards-compatible version would useUnpack.Follow-up: Types are comptime by default?
If we go with this propsal, a potential follow-up would be to make all type annotations comptime by default. This would declutter the syntax and make things more uniform: The static type-language of Guppy would just become Python!
Discussion
Benefits
Monomorphising value parameters in Guppy would also have additional benefits:
Type-level arithmetic
The monomorphisation approach discussed here would also immediately solve our previous problems with expressing type-level arithmetic (see #785). Previously, users had to rely on the workaround of wrapping Guppy functions into Python functions:
With this proposal, the static
n, mparameters can just be turned into generic parameters and the compiler will monomorphise it for us:Generic comptime functions
A long outstanding feature are generic comptime functions. We haven't implement them yet since comptime requires knowledge of array sizes to turn them into Python lists. If all value params are monomorphised, this becomes very easy to support!
Accessing generic parameters in comptime expressions
Furthermore, monomorphisation allows us to access the values of generic parameters inside comptime expressions. This is a feature people have asked for in the past, but would be impossible without monomorphisation in Guppy:
Drawbacks
Performance
The main downside we need to consider is compiler performance. Monomorphising in Python will obviously slower than doing it in Rust. Moreover, this proposal requires that each monomorphisation is type-checked separately!
Type Inference
Finally, note that comptime types will block type inference:
(That's why generic parameters in Zig are never inferred and always need to be specified.)
Especially if we go with the follow-up of making everything comptime by default, we'll need a way to distinguish cases where type inference is possible vs not. I think a good solution would be to test whether the comptime expression tries to inspect the value of any generic parameters, or if they are only used opaquely. The latter case subsumes all currently possible signatures where type inference is fine.
All reactions