Documentation

GaudisCrypt.Syntax.ProgramSyntax

Concrete syntax for programs and procedures #

Surface syntax for the imperative probabilistic language (StmtWithHoles / ProcedureWithHoles from GaudisCrypt). Expression syntax (GaudiExpr[ ] and the $ sigil) is in ExpressionSyntax.lean; module syntax is in ModuleSyntax.lean. See syntax-ideas.md for design notes.

Statements / programs — GaudiProg[ … ] #

A ;-terminated sequence of statements. The statement forms are:

The argument list ( … ) of a call is always required (write () for no arguments).

The sequence may start with var x : T, …; lines, GaudiProg[ var i : Nat; i <- 0; … ], which declare local variables exactly as in a proc (below): each name stands for its slot in the locals of the ProgramState.

Example (a b c : Lens Nat VariableAssignment globals, inc : Procedure …):

GaudiProg[
  a <- $a + 1;
  b, c <- ($a, $a * 2);
  if ($a == 0) { a <- 1; } else { skip; }
  while ($b == 0) { b <- $b + 1; }
  a <- call inc ($a);
]

Procedures — proc (…) [uses (…)] [: R] { … } #

A procedure term:

proc (x : T, y : U) uses (A : (Nat) → Bool, B : (Bool) → Nat) : R {
  var u : V, w : W;     -- zero or more `var …;` lines of local variables
  <statements>
  return e
}

A let/have/letI/haveI statement in the body scopes over the rest of the body and over return e. Body and return value are two separate fields of ProcedureWithHoles, so the binders on the body's spine — those of the procedure's own block, each carrying the rest of it — are repeated around the return value. A binder nested inside an if/while/ block, on the other hand, ends with that block and does not reach return e.

Procedure types and signatures #

-> is used (rather than :) so these nest inside type ascriptions without extra parentheses; they also pretty-print back into this form.

An argument of any of these may be named — procsig (h : G, m : F) -> Bool — which a ProcedureSignature cannot record and which is therefore dropped, except by moduletype, which keeps the names in the @[gaudiProcParamNames] attribute. See the Signature argument lists section below.

Printing #

Statements, procedures and the two type forms all print in this syntax again, and do so round-trip faithfully: parsing what was printed gives the same term back. A variable read prints as §x, the printable spelling of $x. See the Printing section at the end of this file for the delaborators and for the two places where the printed form differs from what one would write by hand.

e.g. proctype (Nat, Bool) -> Nat, proctype (Nat) -> Nat uses ((Nat) → Bool, (Bool) → Nat), procsig (Nat, Bool) -> Nat. Note Procedure (procsig (Nat) -> Nat) = proctype (Nat) -> Nat.

The module type of a procedure, procmod (…) -> R, is in ModuleSyntax.lean.

Syntax for programs (StmtWithHoles) #

Statement syntax over StmtWithHoles h. Each expression position (assignment RHS, sampling distribution, if/while condition) is wrapped with GaudiExpr[ ] so the $x sigil works. An l-value (assignment/sample LHS) is a lens, lifted into the current full state ProgramState by liftLens — so a global Lens a VariableAssignment may be written bare and is lifted with Lens.intoGlobal, and a local variable (a lens into ProgramState) is used as it is.

Surface forms (gaudi_stmt):

skip;
x <- e;                       -- assignment
a, b <- e;   (a,b) <- e;      -- tuple l-value (parens optional), via `Lens.pair`
x <$ e;                       -- sampling (e : a distribution expression)
x <- call p (e₁, …, eₙ);      -- procedure call, result stored in `x`
call p (e₁, …, eₙ);           -- procedure call, result discarded (Lens.throwaway)
if (e) { … } else { … }       -- the `else` branch is optional
while (e) { … }
{ … }                         -- a block (sequence)
let x := e;   have h : P := prf;   letI …;   haveI …;   -- a Lean binder

The call argument list ( … ) is always required (even ()); the arguments form a tuple matching the callee's ParamType. (hole is still deferred.)

The four binder forms are not StmtWithHoles constructors: they are the ordinary Lean term binders. Each carries the statements it scopes over as a nested statement list, so let x := e; followed by more statements is a single gaudi_stmt holding them, and the binder is visible exactly there — in the statements that follow it in its own block, and nowhere else.

The @[gaudiProcParamNames] attribute #

A ProcedureSignature records parameter types only, so the names written in a moduletype field or a module procedure would be lost. They are kept in this attribute instead, on the declaration that names the procedure — a moduletype accessor MT.f, a module's procedure module X.f and its X.f.procedure — so that notation about a procedure can bind its parameters by name even when the procedure itself is abstract (a field of an arbitrary module of a declared module type has no body to read names off).

The attribute's syntax has to be declared under Lean.Parser.Attr — that is the namespace Lean strips to get an attribute's name from its syntax kind — and an initialize block cannot be used in the file that declares it, which is why both live here rather than next to the commands that write them (ModuleSyntax.lean).

@[gaudiProcParamNames x, m] records the parameter names of a procedure-valued declaration. Written by the moduletype and module commands; may also be attached by hand to an axiomatized procedure.

Equations
  • One or more equations did not get rendered due to their size.
Instances For

    The parameter names recorded for a procedure-valued declaration by @[gaudiProcParamNames …], if any. Read with GaudisCrypt.gaudiProcParamNamesAttr.getParam? env declName.

    class GaudisCrypt.LiftLens (M : Type u) :
    Type (max 1 u)

    Lift a program variable used as an l-value into a setter on the full current state ProgramState. Dispatch is on the lens's container M: a global lens (M = VariableAssignment, the globals) is lifted with Lens.intoGlobal, a full-state lens (M = ProgramState, e.g. a local variable localVarLens "x" T) is kept as-is. The content type A is deliberately not a class parameter — resolution then only needs M (always concrete from the argument), and the result's content unifies with the expected type as an ordinary, postponable constraint. (That is what lets a call result l-value resolve even before the callee's sig is known.)

    Instances
      def GaudisCrypt.liftLens {A : Type} {M : Type u} [LiftLens M] (x : Lens A M) :

      User-facing l-value lift; the container M and the content A are inferred. The result is a Setter (l-values only ever set).

      Equations
      Instances For

        The raw (un-lifted) lens for an l-value: a tuple (x, y, …) becomes a nested Lens.pair; a single term is itself. Pairing needs the components to be disjoint lenses in the same container — the Lens.Disjoint instance is resolved at the concrete lenses, so (a, b) requires Lens.Disjoint a b.

        Equations
        • One or more equations did not get rendered due to their size.
        Instances For

          Raw nested Lens.pair of a comma-list of l-value components (each component may itself be a paren-tuple, handled by [lvalRaw|]).

          Equations
          • One or more equations did not get rendered due to their size.
          Instances For

            lval% x: x as an l-value. A setter on the program state is one already and is used as it is (resetSetter S, say: a setter that is not a lens); anything else is a lens and goes through liftLens.

            Equations
            Instances For

              lval% x: x as an l-value. A setter on the program state is one already and is used as it is (resetSetter S, say: a setter that is not a lens); anything else is a lens and goes through liftLens.

              Equations
              • One or more equations did not get rendered due to their size.
              Instances For

                An l-value lifted into the current full state ProgramState. Accepts a single lens, a parenthesised tuple (a, b), or a bare comma-list a, b (top-level parens optional) — all interpreted via Lens.pair — or a single setter on the program state (lval%).

                Equations
                • One or more equations did not get rendered due to their size.
                Instances For
                  Equations
                  • One or more equations did not get rendered due to their size.
                  Instances For
                    Equations
                    • One or more equations did not get rendered due to their size.
                    Instances For
                      Equations
                      • One or more equations did not get rendered due to their size.
                      Instances For
                        Equations
                        • One or more equations did not get rendered due to their size.
                        Instances For
                          Equations
                          • One or more equations did not get rendered due to their size.
                          Instances For
                            Equations
                            • One or more equations did not get rendered due to their size.
                            Instances For
                              Equations
                              • One or more equations did not get rendered due to their size.
                              Instances For
                                Equations
                                • One or more equations did not get rendered due to their size.
                                Instances For
                                  Equations
                                  • One or more equations did not get rendered due to their size.
                                  Instances For
                                    Equations
                                    • One or more equations did not get rendered due to their size.
                                    Instances For
                                      Equations
                                      • One or more equations did not get rendered due to their size.
                                      Instances For
                                        Equations
                                        • One or more equations did not get rendered due to their size.
                                        Instances For
                                          Equations
                                          • One or more equations did not get rendered due to their size.
                                          Instances For
                                            Equations
                                            • One or more equations did not get rendered due to their size.
                                            Instances For
                                              Equations
                                              • One or more equations did not get rendered due to their size.
                                              Instances For
                                                Equations
                                                • One or more equations did not get rendered due to their size.
                                                Instances For
                                                  Equations
                                                  • One or more equations did not get rendered due to their size.
                                                  Instances For

                                                    Translate one statement to a StmtWithHoles term.

                                                    Equations
                                                    • One or more equations did not get rendered due to their size.
                                                    Instances For

                                                      Translate a statement sequence (fold with seq; empty ↦ skip).

                                                      Equations
                                                      • One or more equations did not get rendered due to their size.
                                                      Instances For

                                                        Top-level program bracket.

                                                        Equations
                                                        • One or more equations did not get rendered due to their size.
                                                        Instances For
                                                          Equations
                                                          • One or more equations did not get rendered due to their size.
                                                          Instances For
                                                            Equations
                                                            • One or more equations did not get rendered due to their size.
                                                            Instances For
                                                              Equations
                                                              • One or more equations did not get rendered due to their size.
                                                              Instances For

                                                                The string name of a program variable: the identifier's name, which must be atomic.

                                                                Equations
                                                                • One or more equations did not get rendered due to their size.
                                                                Instances For

                                                                  Reject a name declared twice among the parameters, local variables and holes of one proc (or the vars of one GaudiProg[ ]).

                                                                  Equations
                                                                  • One or more equations did not get rendered due to their size.
                                                                  Instances For

                                                                    The letI binding of a program variable x : T: x stands for its local slot localVarLens "x" T.

                                                                    Equations
                                                                    • One or more equations did not get rendered due to their size.
                                                                    Instances For

                                                                      Wrap inner in the letI bindings bs (outermost first).

                                                                      Equations
                                                                      • One or more equations did not get rendered due to their size.
                                                                      Instances For

                                                                        Lens.id followed by a chain of .ofst (true) / .osnd (false). Used for argument tuples (hoare[ M (x, m) : … ]), no longer for local variables.

                                                                        Equations
                                                                        • One or more equations did not get rendered due to their size.
                                                                        Instances For

                                                                          Steps to reach slot k of a right-nested n-tuple (the last element is un-wrapped, so it needs no final .ofst).

                                                                          Equations
                                                                          Instances For

                                                                            The names a binder declares, each paired with the (shared) declared type.

                                                                            Equations
                                                                            • One or more equations did not get rendered due to their size.
                                                                            Instances For
                                                                              Equations
                                                                              • One or more equations did not get rendered due to their size.
                                                                              Instances For

                                                                                A hole declaration A : (T₁, …, Tₙ) → R (an abstract procedure with no locals).

                                                                                Equations
                                                                                Instances For
                                                                                  Equations
                                                                                  • One or more equations did not get rendered due to their size.
                                                                                  Instances For
                                                                                    partial def GaudisCrypt.ProgramSyntax.rewriteHoles (holeNames : List Lean.Name) (s : Lean.TSyntax `gaudi_stmt) :

                                                                                    Rewrite call A (…) → holecall A (…) for every callee A whose name is a hole (recursing into if/while/block bodies); everything else is left untouched.

                                                                                    Wrap e in the Lean binders on the spine of the statement sequence ss: the let/have/letI/haveI statements of the sequence itself, not those nested inside an if/while/block. Each such statement carries the rest of its sequence, so the spine is a chain — at most one binder per level, recursed into. proc uses this to repeat the body's binders around the return value, which is a separate field of ProcedureWithHoles.

                                                                                    Equations
                                                                                    • One or more equations did not get rendered due to their size.
                                                                                    Instances For

                                                                                      GaudiProg[ var x : T, …; <stmts> ]: a statement sequence with local variables, each bound to its local slot exactly as in a proc. (The form without var lines is the plain GaudiProg[ … ] above.)

                                                                                      Equations
                                                                                      • One or more equations did not get rendered due to their size.
                                                                                      Instances For

                                                                                        Signature argument lists — proc_arg #

                                                                                        The argument list of a procsig/proctype/procmod, and of a proc field of a moduletype, is a list of types, each of which may carry a name: procsig (h : G, m : F) -> Bool. A ProcedureSignature records only the types, so the names are dropped everywhere except by moduletype and module, which put them in @[gaudiProcParamNames].

                                                                                        Deliberately not proc_binder (the named binder of proc/var/using). Serving both from one category would mean adding a bare-type production to it, and a syntax category being global, that production would also turn up in the five positions where a name is mandatory: var Int;, proc (Int) { … } and module X using (Int) would then parse and fail late in ProgramSyntax.parseBinder instead of at the parser.

                                                                                        Equations
                                                                                        • One or more equations did not get rendered due to their size.
                                                                                        Instances For

                                                                                          A named argument slot, x : T. The name is documentation except in a moduletype.

                                                                                          Equations
                                                                                          • One or more equations did not get rendered due to their size.
                                                                                          Instances For

                                                                                            An unnamed argument slot: just the type.

                                                                                            Equations
                                                                                            Instances For

                                                                                              The name (if one was written) and the declared type of one argument slot.

                                                                                              Equations
                                                                                              • One or more equations did not get rendered due to their size.
                                                                                              Instances For

                                                                                                The declared types of an argument list, with the names dropped.

                                                                                                Equations
                                                                                                • One or more equations did not get rendered due to their size.
                                                                                                Instances For

                                                                                                  The names an argument list wrote, none for a slot that was left unnamed.

                                                                                                  Equations
                                                                                                  • One or more equations did not get rendered due to their size.
                                                                                                  Instances For

                                                                                                    An unnamed argument slot from its type — what the unexpanders build, a printed signature having no names to show.

                                                                                                    Equations
                                                                                                    • One or more equations did not get rendered due to their size.
                                                                                                    Instances For

                                                                                                      Procedure type syntax #

                                                                                                      proctype (T, U, V) -> W is the type Procedure { params := [T, U, V], ret := W }, and proctype (…) -> W uses ((A₁,…) → R₁, …) is the corresponding ProcedureWithHoles, whose hole context is built from the listed (nameless) procedure signatures. (Uses -> rather than : so it needs no extra parentheses inside a type ascription.)

                                                                                                      Equations
                                                                                                      • One or more equations did not get rendered due to their size.
                                                                                                      Instances For

                                                                                                        A nameless hole signature (T₁, …, Tₙ) → R inside a proctype … uses (…) clause.

                                                                                                        Equations
                                                                                                        Instances For
                                                                                                          Equations
                                                                                                          • One or more equations did not get rendered due to their size.
                                                                                                          Instances For
                                                                                                            Equations
                                                                                                            • One or more equations did not get rendered due to their size.
                                                                                                            Instances For

                                                                                                              proctype unexpanders. A signature already prints as procsig (…) -> … (the ProcedureSignature.mk unexpander), so we just rewrite Procedure (procsig …) and ProcedureWithHoles … (procsig …) to proctype …. Parameter lists are read off the raw procsig node (a category quotation can't match the sepBy inside the parens).

                                                                                                              If s is a procsig ( … ) -> … node, return its parameter list and return type. (Not private: ModuleSyntax.lean unexpands procmod with it.)

                                                                                                              Equations
                                                                                                              • One or more equations did not get rendered due to their size.
                                                                                                              Instances For
                                                                                                                Equations
                                                                                                                • One or more equations did not get rendered due to their size.
                                                                                                                Instances For
                                                                                                                  Equations
                                                                                                                  • One or more equations did not get rendered due to their size.
                                                                                                                  Instances For

                                                                                                                    Procedure signature syntax #

                                                                                                                    procsig (T, U, V) -> W is the bare ProcedureSignature.mk [T, U, V] W (the same surface form as proctype, minus the holes — a signature has none). By construction Procedure (procsig …) = proctype …. The unexpander is on ProcedureSignature.mk, so any signature with a literal parameter list prints back as procsig (…) -> ….

                                                                                                                    Equations
                                                                                                                    • One or more equations did not get rendered due to their size.
                                                                                                                    Instances For

                                                                                                                      A signature holds no names, so it prints with unnamed argument slots.

                                                                                                                      Equations
                                                                                                                      • One or more equations did not get rendered due to their size.
                                                                                                                      Instances For

                                                                                                                        Printing #

                                                                                                                        Delaborators that render elaborated terms back into the surface syntax above: a procedure built by proc prints as proc (…) uses (…) : R { … }, a statement prints as GaudiProg[ … ], and a Getter standing on its own prints as GaudiExpr[ … ] (with variable reads as the §x sigil, the printable spelling of $x).

                                                                                                                        A Getter prints that way only over a ProgramState, the only carrier GaudiExpr[ ] can build — a Getter a VariableAssignment (an Expr a) would print as something that does not elaborate back. Inside a statement the expression slots are printed by delabGaudiExpr directly, with no GaudiExpr[ ] wrapper, since $/§ already works there.

                                                                                                                        Printing is round-trip faithful: parsing what was printed yields the same term back (ProgramSyntaxTest.lean checks this by printing, re-parsing and re-elaborating). Hence the two places where the printed form deviates from what one would write by hand:

                                                                                                                        A statement the macros did not build (by hand, or left behind by a rewrite) prints too, in a spelling that re-elaborates to a defeq term:

                                                                                                                        Whenever a term does not fit the surface syntax even so — an l-value that is a setter but not a lens, lets that proc would not have generated — the delaborators fail and Lean falls back to its default output. They also step aside under pp.explicit and set_option pp.notation false, and under the dedicated set_option pp.gaudisCrypt false, which switches only them off and leaves the rest of Lean's notation alone — the way to look at the underlying term.

                                                                                                                        pp.gaudisCrypt reaches the delaborators above but not the app_unexpanders further up this file (proctype/procsig, Procedure): UnexpandM is ReaderT Syntax (EStateM Unit Unit) and carries no Options, so an unexpander cannot consult one. Those still print the type as proctype (…) -> R under pp.gaudisCrypt false; pp.notation false turns them off.

                                                                                                                        Surface syntax is printed only when Lean is printing readably, and only while pp.gaudisCrypt is on.

                                                                                                                        Equations
                                                                                                                        • One or more equations did not get rendered due to their size.
                                                                                                                        Instances For

                                                                                                                          Getter.mk fun st => e — what GaudiExpr[ e ] builds — ↦ e. Fails when the state binder really occurs in e, since then e is not expressible in the surface syntax.

                                                                                                                          Equations
                                                                                                                          • One or more equations did not get rendered due to their size.
                                                                                                                          Instances For

                                                                                                                            L.get s, that is Getter.get (Lens.toGetter L) s, ↦ (L, s).

                                                                                                                            Equations
                                                                                                                            • One or more equations did not get rendered due to their size.
                                                                                                                            Instances For

                                                                                                                              f : ProgramState → A ↦ the getter Getter.mk fun st => f CurrentState.state (with f applied β-reduced), which delabGaudiExpr prints as f CurrentState.state. Its get is f up to η, so this is how a function of the state that is not of the shape GaudiExpr[ ] builds is printed faithfully. CurrentState.state is the state GaudiExpr[ ] reads at.

                                                                                                                              Before that, the reads in f are brought into printable form, each step up to defeq: simplifyReads first; then, once the state is CurrentState.state, a read of a lens at it becomes the sigil read §L (sigilReads); and a sigil read at any other state is pinned to it (pinEvals), since §x would read at the current one.

                                                                                                                              CurrentState.state reads the innermost CurrentState, though, and a GaudiExpr[ ] nested in f installs its own: written there, it would read the nested state. When f mentions its argument inside one (occursNested), the state is bound by a Lean let instead, which nothing captures: Getter.mk fun st => let σ := CurrentState.state; f σ, printed as let σ := CurrentState.state; f σ, and the same up to ζ. The binder is named after f's own if f is a lambda, unless that is the name of the getter's own state binder (delabGaudiExpr checks that one is not mentioned).

                                                                                                                              Instances For

                                                                                                                                An expression slot of a statement. What GaudiExpr[ e ] builds prints as e; any other Getter.mk f as f CurrentState.state (getterViaState); and any other getter g as the read §g — §L for a lens L used as a getter. Each re-elaborates to the same getter up to ζ, η and structure η.

                                                                                                                                Equations
                                                                                                                                • One or more equations did not get rendered due to their size.
                                                                                                                                Instances For

                                                                                                                                  Peel n let/have binders whose values satisfy isOk, then run k on the binder names, inside the local context they introduce. With anon, an inaccessible binder is peeled too and reported under its printed name (see binderPrintName).

                                                                                                                                  Program variables #

                                                                                                                                  A parameter or var of a proc (or of a GaudiProg[ var …; ]) is letI-bound, so the term holds its slot localVarLens "x" T at every use and no binder. To print it under its name again, the delaborators

                                                                                                                                  1. collect the slots of the frame — every such term with a literal name, outside nested proc literals (which are frames of their own and print their own variables), together with the parameters;
                                                                                                                                  2. decide which of them print under their name: exactly one type per name (up to reducible defeq), a non-empty name without », and no clash with a constant or a binder of the same name in the frame (a clashing name could not be told apart from the variable when parsing back);
                                                                                                                                  3. bind each printable one to a let-variable of its name, replacing its slot by it, and print that term with the ordinary machinery, which shows the variable as x (§x when read).

                                                                                                                                  A variable that is not printable keeps its slot, which prints as §(localVarLens "x" T) and re-parses to the same term. A parameter that is not printable makes the proc delaborator step aside: the header has to name it.

                                                                                                                                  FrameVar, frameVars, withVarLocals, withExpr and varBinder live in ProgramSyntax and are not private: the hoare[ ] delaborator prints the frame of a statement triple the same way.

                                                                                                                                  (varLens ⟨"x", T, …⟩).intoLocal — what localVarLens "x" T unfolds to, and what a lemma stated over an arbitrary varLens slot leaves behind — ↦ ("x", T).

                                                                                                                                  Equations
                                                                                                                                  • One or more equations did not get rendered due to their size.
                                                                                                                                  Instances For

                                                                                                                                    A program variable of a frame: its name, its type, the occurrences of its slot, and whether it prints under its name.

                                                                                                                                    Instances For

                                                                                                                                      The program variables of the frame whose terms are es: the parameters params first (in order), then every other variable whose slot occurs in es, in order of first occurrence.

                                                                                                                                      Equations
                                                                                                                                      • One or more equations did not get rendered due to their size.
                                                                                                                                      Instances For

                                                                                                                                        Bind each variable of vars to a let-variable of its name, replace its slots in es by it, and run k on the rewritten terms.

                                                                                                                                        Run d on e in place of the current expression.

                                                                                                                                        Equations
                                                                                                                                        Instances For

                                                                                                                                          The binder x : T of a printable variable, as written after var.

                                                                                                                                          Equations
                                                                                                                                          • One or more equations did not get rendered due to their size.
                                                                                                                                          Instances For

                                                                                                                                            A statement sequence: the right seq spine, flattened. A Lean binder wrapping the rest of the sequence (what a let/have statement elaborates to) becomes one statement carrying that rest; have is the nondependent let, which is the only thing that tells the two apart in the term.

                                                                                                                                            partial def GaudisCrypt.spineLetNames (ss : Array (Lean.TSyntax `gaudi_stmt)) :

                                                                                                                                            The names bound by the let/have statements on the spine of a printed statement sequence, outermost first — exactly the binders wrapSpineBinders repeats around the return value. (letI/haveI inline during elaboration, so no binder of theirs is in either term.)