Zulip Chat Archive

Stream: lean4

Topic: Expr.isProp not picking up a Prop


Heather Macbeth (Dec 22 2023 at 21:10):

I'm trying to get a list of the Prop hypotheses in context. I tried this, but it misses some:

import Lean.Elab.Tactic.Basic

open Lean Meta Elab Tactic

elab "test_tactic" : tactic => withMainContext do
  liftMetaTactic <| fun g => do
  -- collect the nontrivial hypotheses
  let mut hyps : Array Expr := #[]
  for h in  getLCtx do
    if !h.isImplementationDetail then
      hyps := hyps.push h.type
  -- find their types
  let hyp_types  hyps.mapM (fun a => do pure (whnfR ( inferType a)))
  trace `debug (fun _ => m!"found hypotheses {hyps} of types {hyp_types}")
  -- run `Expr.isProp`
  trace `debug (fun _ => m!"These ones are Props according to Expr.isProp: {hyp_types.map Expr.isProp}")
  pure [g]

Heather Macbeth (Dec 22 2023 at 21:10):

For example, here it finds h but not h':

set_option trace.debug true

example (h : P  Q) : P  Q := by
  refine Classical.byContradiction fun h' => ?_
  test_tactic
  sorry
/-
[debug] found hypotheses [Prop, Prop, P ∧ Q, ¬(P ∨ Q)] of types [Type, Type, Prop, Prop]

[debug] These ones are Props according to Expr.isProp: [false, false, true, false]
-/

Eric Wieser (Dec 22 2023 at 21:19):

instantiateMVars fixes it

Eric Wieser (Dec 22 2023 at 21:20):

elab "test_tactic" : tactic => withMainContext do
  liftMetaTactic <| fun g => do
  -- collect the nontrivial hypotheses
  let mut hyps : Array Expr := #[]
  for h in  getLCtx do
    if !h.isImplementationDetail then
      hyps := hyps.push h.type
  -- find their types
  let hyp_types  hyps.mapM (fun a => return (instantiateMVars (whnfR ( inferType a))))
  trace[debug] "found hypotheses {hyps} of types {hyp_types}"
  -- run `Expr.isProp`
  trace[debug]  "These ones are Props according to Expr.isProp: {hyp_types.map Expr.isProp}"
  pure [g]

Heather Macbeth (Dec 22 2023 at 21:21):

Thanks! Is there a preferred order, instantiateMVars before or after whnfR?

Eric Wieser (Dec 22 2023 at 21:21):

That is definitely beyond my paygrade!

Eric Wieser (Dec 22 2023 at 21:27):

My preferred approach would be through Qq:

open Qq
elab "test_tactic" : tactic => withMainContext do
  liftMetaTactic <| fun g => do
  -- collect the nontrivial hypotheses
  let mut hyps : Array Expr := #[]
  for h in  getLCtx do
    if !h.isImplementationDetail then
      hyps := hyps.push h.type
  -- find their types
  let hyp_props : Array (Option Q(Prop))  hyps.mapM (fun a => do
    let a  instantiateMVars a
    if let 1, ~q(Prop), P :=  inferTypeQ a then
      pure (some P)
    else pure none)
  trace[debug] "Found props: {hyp_props}"
  pure [g]

Eric Wieser (Dec 22 2023 at 21:29):

Which I guess forced my hand into calling instantiateMVars before

Eric Wieser (Dec 22 2023 at 21:29):

(note that this let matching on inferTypeQ was broken until a month ago, so this pattern isn't very common yet)

Kyle Miller (Dec 22 2023 at 22:44):

If you're doing whnf, you don't need instantiateMVars before but you do need it after.

Kyle Miller (Dec 22 2023 at 22:45):

docs#Lean.Meta.isProp is the function that handles everything for you

Kyle Miller (Dec 22 2023 at 22:47):

My rule of thumb is "be suspicious about matching/recognition functions from Lean.Expr, and try to look for a Lean.Meta version that handles whnf and metavariables for you". There's not a perfect correspondence between these namespaces unfortunately.

Eric Wieser (Dec 22 2023 at 22:55):

This sounds like a great use-case for docstrings on the Expr versions that recommend the Meta versions where possible


Last updated: May 02 2025 at 03:31 UTC