Zulip Chat Archive

Stream: lean4

Topic: Getting expected type in TermElabM


Adam Topaz (Nov 21 2023 at 17:12):

Do we have some way to obtaining the Expr associated to the expected type in TermElabM?
As a basic example, say I want to write a term elaborator foo% that would work in the following cases:

example : Nat := foo%
example : Rat := foo%

giving 0 in the Nat case and 1 in the Rat case, and resulting in an error in all other cases.

Kyle Miller (Nov 21 2023 at 17:20):

Yes you can. It seems the only way to optionally get an expected type at the moment is if you write a separate syntax and term_elab

syntax (name := fooStx) "foo%" : term

@[term_elab fooStx]
def elabFoo : Term.TermElab := fun stx expectedType? => do
  match stx with
  | `(foo%) => ...
  | _ => throwUnsupportedSyntax

Adam Topaz (Nov 21 2023 at 17:20):

Ah great. Thanks Kyle!

Kyle Miller (Nov 21 2023 at 17:21):

There's some syntax for the elab command to require an expected type, but that causes the elaborator to postpone until it knows the expected type, and if it can't know one it throws an error.

Kyle Miller (Nov 21 2023 at 17:21):

I guess that actually would work for you.

Adam Topaz (Nov 21 2023 at 17:22):

What's that syntax?

Kyle Miller (Nov 21 2023 at 17:24):

import Lean

open Lean Elab Term

elab "foo%" : term <= expectedType => do
  let expectedType  instantiateMVars expectedType
  match expectedType with
  | .const ``Nat .. => elabTerm ( `((37 : Nat))) none
  | .const ``Rat .. => elabTerm ( `((17 : Rat))) none
  | _ => throwError "The expected type should be Nat or Rat, not{indentD expectedType}"

example : Nat := foo%
example : Rat := foo%

Adam Topaz (Nov 21 2023 at 20:09):

All the discussion about iterated products in Tao's PFR project made me curious about how automation could help. So I made an elaborator that automatically constructs "obvious" equivalences between iterated products, regardless of how they're associated. The reason for my question is that I wanted to make this as convenient as possible to use. There are two variants now: prod_assoc% for when the types can be infered and prod_assoc(..., ...) requiring the user to provide them explicitly. This still feels hacky to me. Does anyone have any suggestions for how to best make this work?

the draft PR is here: #8551 (with examples at the bottom of the file)

Kyle Miller (Nov 21 2023 at 20:14):

You could avoid the special case of prod_assoc(..., ...) by using the syntax

(prod_assoc% : (α × β) × (γ × δ)  α × (β × γ) × δ)

Adam Topaz (Nov 21 2023 at 20:15):

Sure, that's only slightly more verbose than prod_assoc(..., ...)

Adam Topaz (Nov 21 2023 at 20:15):

What I really want is to be able to write prod_assoc(_, ...) if I know that the input can be inferred but not the output, and similarly with the two interchanged.

Adam Topaz (Nov 21 2023 at 20:16):

But maybe (prod_assoc% : _ ≃ α × (β × γ) × δ) is good enough in that case.

Adam Topaz (Nov 21 2023 at 20:21):

Hmm.... This still fails:

elab "associate%" : term <= expectedType => do
  match expectedType with
    | .app (.app (.const ``Equiv _) a) b => do
      mkProdEquiv a b
    | _ => throwError "Expected type {expectedType} is not of the form `α ≃ β`."

example {α β γ δ : Type*} (x : (α × β) × (γ × δ)) : α × (β × γ) × δ := associate% x

Do you have any hints for how to make this work?

Kyle Miller (Nov 21 2023 at 20:24):

I just got this example to work:

example : (α × β) × (γ × δ)  α × (β × γ) × δ :=
  (prod_assoc% : _  α × β × γ × δ).trans prod_assoc%

Kyle Miller (Nov 21 2023 at 20:24):

code

Adam Topaz (Nov 21 2023 at 20:25):

Nice! I'll take a closer look after I eat some lunch :)

Adam Topaz (Nov 21 2023 at 20:36):

Awesome! with your code Kyle this works as well:

example {α β γ δ : Type*} (x : (α × β) × (γ × δ)) : α × (β × γ) × δ := prod_assoc% x

Adam Topaz (Nov 21 2023 at 20:45):

I think that PR should be ready to review now :) Thanks again Kyle!

Kyle Miller (Nov 21 2023 at 21:37):

I'm enjoying these Lean 4 days of Lean. We've got a lot of flexibility now!


Last updated: Dec 20 2023 at 11:08 UTC