Zulip Chat Archive

Stream: lean4

Topic: Creating Expr objects


Calle Sönne (May 15 2024 at 20:37):

I'm trying to learn some basic metaprogramming, and I'm currently trying to understand the implementation of the tacticcancel_denoms in mathlib. I want to experiment a bit with its helper functions, such as findCancelFactor, which takes e : Expr as an argument. Is there a way to conveniently write down non-trivial expressions to test this function, such as for example 5x/10 + 23y/2, without having to manually write down the corresponding Expr object?

Adam Topaz (May 15 2024 at 20:39):

This is what Qq is for.

Adam Topaz (May 15 2024 at 20:41):

import Lean
import Qq

open Lean Qq

open Qq in
example (x y : Q(Rat)) : Q(Rat) :=
  q(5 * $x / 10 + 23 * $y / 3)

example : Q(Rat) = Expr := rfl

Calle Sönne (May 15 2024 at 20:42):

Adam Topaz said:

import Lean
import Qq

open Lean Qq

open Qq in
example (x y : Q(Rat)) : Q(Rat) :=
  q(5 * $x / 10 + 23 * $y / 3)

example : Q(Rat) = Expr := rfl

Amazing, thanks a lot!

Adam Topaz (May 15 2024 at 20:44):

But beware that Qq is unfortunately still difficult to use.

Calle Sönne (May 15 2024 at 20:46):

Yeah, I was just going to ask if there was any place I could read more about it. I came across it before in cancel_denoms but I struggled to find documentation about it then

Eric Wieser (May 15 2024 at 21:13):

I promised at some point to write some tutorial-like documentation for it, but that hasn't happened yet...

Kyle Miller (May 16 2024 at 03:19):

If you want to see how to generate an Expr, you could use the Mathlib ToExpr Expr instance:

import Mathlib.Tactic

open Lean Elab Command Term in
elab "#expr " t:term : command => do
  let e  liftTermElabM do elabTermAndSynthesize t none
  logInfo m!"{toExpr e}"

#expr fun (x : Rat) => 5*x/10
/-
Lean.Expr.lam `x (Lean.Expr.const `Rat [])
  (((((((Lean.Expr.const `HDiv.hDiv [Lean.Level.zero, Lean.Level.zero, Lean.Level.zero]).app
                        (Lean.Expr.const `Rat [])).app
                    (Lean.Expr.const `Rat [])).app
                (Lean.Expr.const `Rat [])).app
            (((Lean.Expr.const `instHDiv [Lean.Level.zero]).app (Lean.Expr.const `Rat [])).app
              (Lean.Expr.const `Rat.instDiv []))).app
        (((((((Lean.Expr.const `HMul.hMul [Lean.Level.zero, Lean.Level.zero, Lean.Level.zero]).app
                              (Lean.Expr.const `Rat [])).app
                          (Lean.Expr.const `Rat [])).app
                      (Lean.Expr.const `Rat [])).app
                  (((Lean.Expr.const `instHMul [Lean.Level.zero]).app (Lean.Expr.const `Rat [])).app
                    (Lean.Expr.const `Rat.instMul []))).app
              ((((Lean.Expr.const `OfNat.ofNat [Lean.Level.zero]).app (Lean.Expr.const `Rat [])).app
                    (Lean.Expr.lit (Lean.Literal.natVal 5))).app
                ((Lean.Expr.const `Rat.instOfNat []).app (Lean.Expr.lit (Lean.Literal.natVal 5))))).app
          (Lean.Expr.bvar 0))).app
    ((((Lean.Expr.const `OfNat.ofNat [Lean.Level.zero]).app (Lean.Expr.const `Rat [])).app
          (Lean.Expr.lit (Lean.Literal.natVal 10))).app
      ((Lean.Expr.const `Rat.instOfNat []).app (Lean.Expr.lit (Lean.Literal.natVal 10)))))
  Lean.BinderInfo.default
-/

Yaël Dillies (May 16 2024 at 04:44):

Eric Wieser said:

I promised at some point to write some tutorial-like documentation for it, but that hasn't happened yet...

I think this was a shared promise and I'm not out of exams before a month, so...


Last updated: May 02 2025 at 03:31 UTC