Zulip Chat Archive
Stream: new members
Topic: Syntax to parse binary strings
Fady Adal (Aug 09 2024 at 18:51):
Hello!
I am trying to embed a DSL to be able to write qubit states in string form (e.g. ∣0100⟩
) and be able to translate them to kronecker products. Part of that means I want to have a syntax like the following:
syntax (name := qubits) "∣" ("0" <|> "1")+ "⟩" : term
But doing so tells me that "0"
is an "invalid atom".
I know one compromise I can make it to have
syntax (name := qubits) "∣" char+ "⟩" : term
@[macro qubits] def qubitsImpl : Macro
| `( ∣ $bits* ⟩ ) => do
let bools ← bits.mapM fun bit =>
match bit.getChar with
| '0' => `(false)
| '1' => `(true)
| _ => Macro.throwError "Invalid qubit string"
`([$bools,*])
| _ => Macro.throwUnsupported
But this would make me have to specify qubits as ∣'0''0'⟩
which is too verbose. Similarly, if I use the num
syntax ∣00⟩
is understood as just ∣0⟩
.
I there a way to make a new syntax
that parses binary strings, without having to resort to either num
or char
or in a way to addresses those hiccups I laid out?
Thank you so much
Asei Inoue (Dec 22 2024 at 07:23):
I'm interesed in this problem!
Soundwave (Dec 22 2024 at 07:43):
Fady Adal said:
Similarly, if I use the
num
syntax∣00⟩
is understood as just∣0⟩
.
Is it?
Give me a moment
Soundwave (Dec 22 2024 at 07:52):
cf.:
elab (name := qubits) "∣" n:num "⟩" : term => do
let bits := (n.raw.getArg 0).getAtomVal.data.map λc ↦
match c with
| '0' => false
| '1' => true
| _ => false -- You can handle this better but you get the idea
Lean.Elab.Term.elabTerm (Lean.Quote.quote (k := `term) bits) none
def test := ∣00⟩
#eval test
Soundwave (Dec 22 2024 at 07:54):
The lesson is perhaps that TSyntax needs lots of love to be immensely useful.
Fady Adal (Dec 22 2024 at 19:59):
You're correct. I don't remember what I was doing wrong but I ended up figuring it out and forgot to update this thread. My solution for reference (which I think might be overcomplicating it):
syntax (name := kets) "∣" num "⟩" : term
@[macro kets] def ketsImpl : Macro
| `(∣ $n ⟩ ) => do
let digits := (n.raw.isLit? `num).get!.toList
let qubits ← (digits.mapM fun d => do
match d with
| '0' => ``(ket0)
| '1' => ``(ket1)
| _ =>
Macro.throwError s!"invalid qubit state: expected 0 or 1, got {d}")
mkKronChain qubits
| _ => Macro.throwUnsupported
Soundwave (Dec 22 2024 at 20:35):
Nope, looks good. I'm not super familiar with all the Syntax helpers myself. Don't need to check for being a num lit though, as it's the only thing you'll get from the num parser.
Kyle Miller (Dec 22 2024 at 20:58):
It's possible for it to not be a num lit. For example, in ∣⟩
the num will be Syntax.missing
. It's best to throwUnsupportedSyntax
if it's not actually a number literal.
There are also number literals that aren't decimal sequences, like for example you might come across ∣0x22⟩
.
Soundwave (Dec 22 2024 at 21:45):
Curious. I didn't realize the parser could throw an error but elaboration could succeed... Good to know.
elab (name := qubits) "∣" n:num "⟩" : term => do
let `($bits) := n
dbg_trace "{bits}"
if bits.raw matches Lean.Syntax.missing then
Lean.Elab.Term.elabTerm (Lean.Quote.quote (k := `term) 2) none
else
let bits := (n.raw.getArg 0).getAtomVal.data.map λc ↦
match c with
| '0' => false
| '1' => true
| _ => false
Lean.Elab.Term.elabTerm (Lean.Quote.quote (k := `term) bits) none
def test := ∣⟩ -- Error here...
#eval test -- ...but term is still elaborated!
Soundwave (Dec 22 2024 at 21:51):
Introduces another caveat to relying on TSyntax: missing will appear as a correctly typed default value.
Last updated: May 02 2025 at 03:31 UTC