Zulip Chat Archive

Stream: new members

Topic: applying one expr to another


Lucas Allen (Sep 05 2020 at 07:44):

Buenos días, Giving two expressions t s I want to be able to treat s like it's a goal, apply t to it, and get the list of goals that apply t generates. To do this I have

meta def test3 (t s : expr) : tactic (list expr) :=
do set_goals [s],
   apply t,
   get_goals

meta def test3_works (t s : expr) : tactic unit :=
do l  test3 t s,
   trace l

variables c d : Prop
#eval test3_works `( {a b : Prop}, (a  b)  (b  a)  (a  b)) `(c  d)

Unfortunately, I get a red squiggle under the in (c ↔ d) with the error "failed to synthesize type class instance for
c d : Prop ⊢ reflected (c ↔ d)". I've seen reflected before, but I have no idea what it is.

Does test3 actually do what I want? And if so, how might I test it? Is it even possible to test?

Fox Thomson (Sep 06 2020 at 15:38):

Your problem is not related to test3 or iff. I think an expression being reflected refers to it being free of any local context so '(c ↔ d) is not reflected as it refers to c and d. '(∀ {c d : Prop} c ↔ d) would be reflected. In order to fix this you can change c and d to exprand use pre-expresions ''(%%c ↔ %%d) like in this:

meta def test3 (t : expr) (s : pexpr) : tactic (list expr) :=
do (λ x : expr, [x]) <$> to_expr s >>= set_goals,
   apply t,
   get_goals

meta def test3_works (t : expr) (s : pexpr) : tactic unit :=
do l  test3 t s,
   trace l

variables c d : expr

#eval test3_works `( {a b : Prop}, (a  b)  (b  a)  (a  b)) ``(%%c  %%d)

Unfortunately this was as far as I got, lean gives the cryptic error cannot evaluate function: 0 arguments given but expected 2

Lucas Allen (Sep 06 2020 at 22:04):

I see, thanks. I've gotten the error "cannot evaluate function: 0 arguments given but expected 2" before as well and I have no idea what it means.

Lucas Allen (Sep 06 2020 at 22:05):

It gives the impression that there are some arguments missing, but I don't know what they could be.

Reid Barton (Sep 06 2020 at 22:09):

Apparently that error happens when you try to #eval something involving a variable:

variables (n : )
#eval n   -- error: cannot evaluate function: 0 arguments given but expected 1

Reid Barton (Sep 06 2020 at 22:10):

In this case that error makes sense because ``(%%c ↔ %%d) means iff applied to the expressions c and d.

Reid Barton (Sep 06 2020 at 22:11):

For testing purposes I guess you might prefer constants c d : Prop together with ``(c ↔ d), although then you will encounter a new error.

Lucas Allen (Sep 06 2020 at 22:12):

I'm not at my Lean machine atm, I'll check it out later. Are %%c and %%d variables?

Reid Barton (Sep 06 2020 at 22:13):

they are splices

Reid Barton (Sep 06 2020 at 22:14):

like if c : exprand d : expr both represent the expression x, then ``(%%c ↔ %%d) is the expression x ↔ x

Lucas Allen (Sep 06 2020 at 22:14):

My understanding was that splices were like _s but you can use the name later.

Reid Barton (Sep 06 2020 at 22:17):

I don't understand what that would mean. It sounds more like metavariables...?

Reid Barton (Sep 06 2020 at 22:17):

%%c can also be called an antiquotation

Reid Barton (Sep 06 2020 at 22:23):

As an extreme example, ``(%%c) = c.

Lucas Allen (Sep 06 2020 at 22:23):

Hmmm, maybe my understanding is wrong. Can't you do things like (%%c ↔ %%d)) ← get_some_expr, and then use c and d later?

Lucas Allen (Sep 06 2020 at 22:24):

Is this explained in some docs somewhere?

Reid Barton (Sep 06 2020 at 22:25):

That's the same thing but in a pattern position.

Lucas Allen (Sep 06 2020 at 22:27):

Right.

Lucas Allen (Sep 07 2020 at 07:22):

I tried

meta constants x y : expr
#eval test3_works `( {a b : Prop}, (a  b)  (b  a)  (a  b)) `(%%x  %%y)

And got a red squiggle under #eval with the error "code generation failed, VM does not have code for 'y'".

I feel like I'm trying to do something for which Lean is not intended. I'm going to go away and think about what I've learned and what I want to do.

Reid Barton (Sep 07 2020 at 11:20):

This is still the same underlying issue--you're asking Lean to do something that doesn't make sense. You might like to consider the following exercises.

Why does this fail? (What do you expect to happen?)

variables (n : nat)
#eval n

Why does this fail?

constant (n : nat)
#eval n

Why does this fail?

meta constant (e : expr)
#eval trace e

Why does this fail?

meta constant (e : expr)
#eval trace ``(%%e)

Then: Why does this fail?

variable (n : nat)
#eval trace ``(n)

Why does this not fail?

constant (n : nat)
#eval trace ``(n)

Lucas Allen (Sep 08 2020 at 06:43):

The code

variables (n : )
#eval n

gives the error "cannot evaluate function: 0 arguments given but expected 1". I guess this is because #eval does computation, so it wants the variable n to be assigned to something.

constant (n : nat)
#eval n

gives "code generation failed, VM does not have code for 'm'". I'm guessing this is because #eval doesn't know what to do with constants.

meta constant (e : expr)
#eval trace e

gives "code generation failed, VM does not have code for 'e'" which I'd wager is for the exact same reason as the last example.

meta constant (e : expr)
#eval trace ``(%%e)

gives the same error I think because ``(%%e) is just e.

variable (n : nat)
#eval trace ``(n)

gives a red squiggle under the n with the error "unexpected local in quotation expression". This suggests to me that when a variable is declared a local constant is added to the environment or something. Whereas for

constant (n : nat)
#eval trace ``(n)

Lean stores n as a constant. So do double backticks work on constants and not local constants or something?

Lucas Allen (Sep 08 2020 at 06:45):

So this

meta constants x y : expr
#eval test3_works `( {a b : Prop}, (a  b)  (b  a)  (a  b)) `(%%x  %%y)

fails because x and y are not set to anything. Right?

Mario Carneiro (Sep 08 2020 at 07:23):

So do double backticks work on constants and not local constants or something?

This has to do with the difference between double and triple backtick. A double backtick pre-expression is name-resolved in the empty context at the point of the tactic itself, which is to say, you can reference constants and definitions defined previous to the tactic call, but not local constants (which wouldn't make any sense anyway because lean wants an expr not a nat at that point; but this is what %%e is doing).

When you use triple backtick, all the resolution is put off until it is explicitly elaborated using to_expr. This approach allows you to resolve local constants as long as the to_expr tactic is called inside a begin ... end block that has n in the context.

Mario Carneiro (Sep 08 2020 at 07:25):

So this fails because x and y are not set to anything. Right?

It fails for the same reasons as examples 2 and 3. The VM can't evaluate constants (unless they have been specifically defined as intrinsics in the C++ code)

Lucas Allen (Sep 08 2020 at 08:00):

Ohh...

variable (n : nat)
#eval trace ```(n)

works.

Mario Carneiro (Sep 08 2020 at 08:00):

You should think of that as being morally equivalent to trace "n"

Mario Carneiro (Sep 08 2020 at 08:01):

it doesn't require n in the context at all

Lucas Allen (Sep 08 2020 at 08:01):

I'm not sure I completely understand what's happening. But I think I is learning.

Lucas Allen (Sep 08 2020 at 08:09):

Yeah, so

#eval trace ```(t)

works without variable t : nat.

Mario Carneiro (Sep 08 2020 at 08:34):

open tactic

meta def tac := to_expr ```(t) >>= trace

#eval tac -- unknown identifier 't'

example (t : nat) : true := by {tac, trivial} -- t

Mario Carneiro (Sep 08 2020 at 08:36):

or to be slightly more interesting:

open tactic

meta def tac := to_expr ```(t) >>= infer_type >>= trace

#eval tac -- unknown identifier 't'

example (t : nat) : true := by {tac, trivial} -- ℕ

Mario Carneiro (Sep 08 2020 at 08:36):

which should make it clear that in the latter case tac really has picked up the variable t : nat in the context


Last updated: Dec 20 2023 at 11:08 UTC