Zulip Chat Archive

Stream: metaprogramming / tactics

Topic: pattern-matching `match`


Jon Eugster (May 28 2025 at 14:01):

What's wrong with the following syntax pattern matching and how would I match syntax of the form fun x => match x with ...?

import Lean
-- import Mathlib

open Lean PrettyPrinter.Delaborator Parser

/-- Delaborator for functions on products like `α × β → γ`. -/
@[delab lam]
def delabMy : Lean.PrettyPrinter.Delaborator.Delab :=
  whenPPOption getPPNotation do
  let stx  delabLam
  match stx with
    | `(fun $x  match $x with | ($m, $n) => $body) => -- Error
      `(fun ($m, $n)  $body)
    | _ => pure stx

example : True := by
  let myAdd : Nat × Nat  Nat := fun (m, n)  m + n
  /-
  myAdd : ℕ × ℕ → ℕ × ℤ := fun x ↦ match x with | (m, n) => ↑m + ↑n
  ⊢ False
  -/
  trivial

Jon Eugster (May 28 2025 at 14:49):

My solution now is the following, which feels very messy:

import Lean

open Lean PrettyPrinter.Delaborator

/-- Delaborator for functions on products like `α × β → γ`. -/
@[delab lam]
def delabLamTuple : Lean.PrettyPrinter.Delaborator.Delab :=
  -- TODO: add the right options from Lean.PrettyPrinter.Delaborator.Options
  -- here, so that `set_option pp.XXX` has de desired effect.
  whenPPOption getPPNotation do
  let stx  delabLam
  match stx with
  | `(fun $x  $body) =>
    -- TODO: I expected the following syntax pattern match to work:
    -- | `(fun $x ↦ match $x with | ($m, $n) => $body) => `(fun ($m, $n) ↦ $body)
    -- What follows now is a tedious manual match through the entire syntax tree
    -- which is quite error-prone.

    -- We extract the following variables: "match `x₁` with | (`m`, `n`) => `body₁`"
    match body.raw with
    | .node _ ``Lean.Parser.Term.match #[_, _, _,
        (.node _ `null #[.node _ ``Lean.Parser.Term.matchDiscr #[_, x₁]]), _, alts₀] =>
      if x == x₁ then
        match alts₀ with
        | (.node _ ``Lean.Parser.Term.matchAlts #[(.node _ `null #[
            (.node _ ``Lean.Parser.Term.matchAlt #[_, alts₁, _, body₁])])]) =>
          match alts₁ with
          | .node _ `null #[(.node _ `null #[
              (.node _ `Lean.Parser.Term.tuple #[_,
                (.node _ `null #[m, _, (.node _ `null #[n])]), _])])] =>
            let body₁ : TSyntax `term := body₁
            let m : TSyntax `term := m
            let n : TSyntax `term := n
            `(fun ($m, $n)  $body₁)
          | _ => pure stx
        | _ => pure stx
      else pure stx
    | _ => pure stx
  | _ => pure stx

example : True := by
  let myAdd : Nat × Nat  Nat := fun (m, n)  m + n
  trivial

Kyle Miller (May 28 2025 at 15:11):

It's one of these issues where you need to be explicit about the antiquotes (use the full form with the syntax name $x:ident rather than the abbreviated form $x).

@[delab lam]
def delabMy : Lean.PrettyPrinter.Delaborator.Delab :=
  whenPPOption getPPNotation do
  let stx  delabLam
  match stx with
    | `(fun $x:ident  match $x':ident with | ($m, $n) => $body) =>
      guard <| x == x'
      `(fun ($m, $n)  $body)
    | _ => pure stx

Kyle Miller (May 28 2025 at 15:14):

I'm also trying to fix a bug: using $x in both places doesn't do an equality check, but rather it's two different patterns.

I'm not completely sure that checking equality with x == x' is completely correct, but it seems to work here for reasons I don't understand (I'd have to look into the core delaborator code). If that doesn't work in general, you could do x.getId == x'.getId, which should be ok since the delaborator handles shadowing.

Jon Eugster (May 28 2025 at 15:18):

Thank you Kyle :D


Last updated: Dec 20 2025 at 21:32 UTC