[I recognize that modular implicits would help with this, but I’m asking b/c I would like solutions now, and modular implicits are years away.]
I’m hacking away on a quantum circuit compiler, and in such a thing, there are a ton of things that you need to manage:
- physical quantum bits (== registers)
- physical classical bits
- logical quantum bits
- gate-names
- quantum variables
- classical variables
- pairs of logical quantum bits
and probably other things I’ve forgotten. For many/most of these, if one wants to give decent error-messages, one wants to have a location as part of the data-structure. Which means you have a non-structural equality on the type. And then, you want sets of them, and maps with them as a key, and sometimes bijections where both domain and range are one of these types (e.g. a “layout” is a bijection between physical and logical quantum bits).
And so, I end up extending Map
and Set
with a few more operations (like pp_hum
for human-readable pretty-printing, in addition to that provided by deriving.show
) and then applying those functors to a large number of types. And it all works great.
Now I come to write code, and it all look like this:
let qvl = QVSet.(toList (union qvfvs (ofList qvl))) in
let cvl = CVSet.(toList (union cvfvs (ofList cvl))) in
....
let qwires = qubits |> List.map (AB.QUBMap.swap_find qubit2wire) |> List.map snd in
let cwires = clbits |> List.map (AB.CLBMap.swap_find clbit2wire) |> List.map snd in
and on and on. All over the place, there are these module-names. I can’t open
them, b/c … which one would I open? And if I open one, I still have to use identically-named members of other modules, so it doesn’t help much.
Anyway, maybe there’s no solution other than to keep going this way. But I figured I’d ask if others had some scheme for dealing with this.