Zulip Chat Archive

Stream: new members

Topic: expr: fields and @


Fabian Glöckle (Apr 17 2019 at 20:17):

Hello everyone, in meta I am trying to build an expr for @has_add.add _ _ _ _. How are class/structure fields and the @-notation implemented? When I ask expr.app_fn about to_expr ``(@has_add.add), I get has_add.add. (?)

Fabian Glöckle (Apr 17 2019 at 20:50):

To be more precise, I want the has_add.add part to be dynamic (generated from a string to also support has_mul.mul etc.); the @is always needed.

Fabian Glöckle (Apr 17 2019 at 22:08):

Is the @ an annotation? My tests indicate no...

meta def diagnose : tactic (option (name × expr)) :=
do exp  to_expr ``(@has_add.add),
   res  pure $ expr.is_annotation exp,
   type  infer_type exp,
   trace type,
   trace res,
   return res

--> trace output:

Π {α : Type ?} [c : has_add α], α  α  α
none

without the @:

?m_1  ?m_1  ?m_1
none

Simon Hudon (Apr 18 2019 at 00:13):

@ is used by the elaborator. It is only present pre-terms (i.e. pexpr). Consider:

meta def foo : tactic unit :=
do let e := ``(@has_add.add ),
   tactic.trace e.to_raw_fmt,
   tactic.trace e.is_annotation,
   let e := ``(has_add.add ),
   tactic.trace e.to_raw_fmt,
   tactic.trace e.is_annotation

run_cmd foo

Simon Hudon (Apr 18 2019 at 00:13):

It prints:

[macro annotation (const has_add.add [])]
(some (@, has_add.add))
(const has_add.add [])
none

Simon Hudon (Apr 18 2019 at 00:14):

``(@has_add.add) is a pre-term but to_expr makes it into a term

Keeley Hoek (Apr 18 2019 at 01:25):

I'm not sure what you want it to "behave like @ for", but be aware of tactic.mk_mapp which lets you provided all of the (even implicit) arguments implicitly or explicitly.

Fabian Glöckle (Apr 22 2019 at 21:31):

Thanks!
@Simon Hudon Can I add this annotation to an arbitrary application pexpr? (No, because meta constant macro_def : Type belongs to the kernel?!)
@Keeley Hoek Can I build such an app which involves terms of the form var <n> I which I can bind later on? (I got failed to infer type, unexpected bound variable occurrence when using var`terms which are not (yet) bound.)

Fabian Glöckle (Apr 22 2019 at 21:33):

My goal is to add a declaration like

def has_add_compatible :=
λ (α : Type u) (β : Type v) [i₁ : has_add α] [i₂ : has_add β] (f : α  β),
   {x y}, f (@has_add.add α i₁ x y) = @has_add.add β i₂ (f x) (f y)

to the environment with has_add.addbeing a template parameter which could also be set to has_mul.mul.

Fabian Glöckle (Apr 23 2019 at 15:03):

Do my questions make sense? Can I further elaborate on anything? Any help is appreciated :slight_smile:

Simon Hudon (Apr 23 2019 at 15:28):

Hey! Sorry I forgot to answer

Simon Hudon (Apr 23 2019 at 15:30):

You don't need to generate @ to create that definition. The following has the same effect:

do add <- mk_const has_add.add,
   return $ add α i₁ x y

Simon Hudon (Apr 23 2019 at 15:31):

or more simply: mk_mapp `has_add.add [α,i₁,x,y]

Simon Hudon (Apr 23 2019 at 15:34):

While in writing an expression like @has_add.add α i₁ x y you need the added tool of @ to specify implicit arguments, in building expr trees, you have to work harder if you want to omit an implicit argument. That's because app f x means the same whether the type of the expression f is Π x : t, t' or Π {x : t}, t'.

Simon Hudon (Apr 23 2019 at 15:37):

If you want to omit the first implicit argument, you have to first discover that it is indeed an implicit argument, then, you have to create a meta variable v of the right type and feed it to f: app f v. Then you have "omitted" the first arguments: you're relying on unification to figure out what it is

Simon Hudon (Apr 23 2019 at 15:38):

You can also use tactic.mk_app which behaves very similarly to what I described

Fabian Glöckle (Apr 23 2019 at 18:16):

Great, thanks, that clears up my questions about how app works for exprand pexpr!

Fabian Glöckle (Apr 23 2019 at 18:18):

I was trying to mix this with reflected code like in the following, is that possible?

meta def add_compatible_def (x : string) : command :=
do let has_x_name := name.mk_string (string.append "has_" x) name.anonymous,
   let has_x_x_name := name.mk_string x has_x_name,
   has_x  mk_const has_x_name,
   has_x_x  mk_const has_x_x_name,
   decl_type  to_expr ``(Π (α : Type) (β : Type) [%%has_x α] [%%has_x β], (α  β)  Prop),
   decl_body  to_expr ``(λ (α : Type) (β : Type) [i₁ : %%has_x α] [i₂ : %%has_x β] (f : α  β),
                           {x y : α}, f (%%has_x_x α i₁ x y) = %%has_x_x β i₂ (f x) (f y)),
   decl  pure $ mk_definition `compatible [`u, `v] decl_type decl_body,
   add_decl decl

Fabian Glöckle (Apr 23 2019 at 18:19):

Currently the reflected code does not accept the arguments this way:

failed to synthesize type class instance for
α β : Type,
i₁ : has_add α,
i₂ : has_add β,
f : α  β,
x y : α
 has_add Type
Additional information:
context: switched to simple application elaboration procedure because failed to use expected type to elaborate it, error message
  too many arguments

Simon Hudon (Apr 23 2019 at 18:27):

Instead of using Π and λ in your quasiquotes, use mk_local' to create variables like α and β and the instances, then you use to_expr and quasiquotes to create ``((%%α → %%β) → Prop)and you use pis to create the pis and similarly with lambdas to create the lambdas.

Fabian Glöckle (Apr 23 2019 at 19:04):

very convenient :)
I tried:

meta def add_compatible_def (x : string) : command :=
do let has_x_name := name.mk_string (string.append "has_" x) name.anonymous,
   let has_x_x_name := name.mk_string x has_x_name,
   has_x  mk_const has_x_name,
   has_x_x  mk_const has_x_x_name,
   α  mk_local' `α binder_info.default (sort (level.succ level.zero)),
   β  mk_local' `β binder_info.default (sort (level.succ level.zero)),
   i₁  mk_local' `i₁ binder_info.inst_implicit (has_x α),
   i₂  mk_local' `i₂ binder_info.inst_implicit (has_x β),
   type_main  to_expr ``((%%α  %%β)  Prop),
   let decl_type := expr.pis [α, β, i₁, i₂] type_main,
   f  mk_local' `f binder_info.default (pi `a binder_info.default α β),
   x  mk_local' `x binder_info.implicit α,
   y  mk_local' `y binder_info.implicit α,
   app₁  mk_app has_x_x_name [α, i₁, x, y],
   app₂  mk_app has_x_x_name [β, i₂, (f x), (f y)],
   body_main  to_expr ``(%%f (%%app₁) = %%app₂),
   let decl_body := expr.lambdas [α, β, i₁, i₂, f] (expr.pis [x, y] body_main),
  --  decl_body ← to_expr ``(λ (α : Type) (β : Type) [i₁ : %%has_x α] [i₂ : %%has_x β] (f : α → β),
  --                         ∀ {x y : α}, f (%%has_x_x α i₁ x y) = %%has_x_x β i₂ (f x) (f y)),
   trace decl_type,
   trace decl_body,
   decl  pure $ mk_definition `compatible [`u, `v] decl_type decl_body,
   add_decl decl

It throws

[app_builder] failed to create an 'has_add.add'-application, failed to solve unification constraint for #2 argument (has_add α =?= has_add α)

What is the mistake?

Simon Hudon (Apr 23 2019 at 19:05):

use mk_mapp instead of mk_app

Fabian Glöckle (Apr 23 2019 at 19:08):

replacing with

   app₁  mk_mapp has_x_x_name [some α, some i₁, some x, some y],
   app₂  mk_mapp has_x_x_name [some β, some i₂, some (f x), some (f y)],

?

Simon Hudon (Apr 23 2019 at 19:11):

Yes

Simon Hudon (Apr 23 2019 at 19:11):

Instead of has_x_x_name you can use ``has_add.add

Fabian Glöckle (Apr 23 2019 at 19:12):

Replacing these lines I still get the same error

[app_builder] failed to create an 'has_add.add'-application, failed to solve unification constraint for #1 argument (has_add α =?= has_add α)

Fabian Glöckle (Apr 23 2019 at 19:13):

Instead of has_x_x_name you can use ``has_add.add

Yes, in the end I wanted to be able to write add_compatible_def "mul" or similar

Simon Hudon (Apr 23 2019 at 19:13):

try putting set_option pp.implicit true before your proof

Fabian Glöckle (Apr 23 2019 at 19:15):

I put it above the definition, but to no effect..

Simon Hudon (Apr 23 2019 at 19:15):

The error message should change

Fabian Glöckle (Apr 23 2019 at 19:16):

still

[app_builder] failed to create an 'has_add.add'-application, failed to solve unification constraint for #2 argument (has_add α =?= has_add α)

Fabian Glöckle (Apr 23 2019 at 19:16):

the number of the argument? #1 and #2

Simon Hudon (Apr 23 2019 at 19:17):

Try replacing some i₁ with none

Fabian Glöckle (Apr 23 2019 at 19:18):

[app_builder] failed to create an 'has_add.add'-application, there are missing implicit arguments

Simon Hudon (Apr 23 2019 at 19:25):

If you add infer_type app₁ >>= trace before mk_mapp, what does it print?

Fabian Glöckle (Apr 23 2019 at 19:27):

we don't reach this point

Fabian Glöckle (Apr 23 2019 at 19:28):

i.e. still the error

Simon Hudon (Apr 23 2019 at 19:29):

How far does it get?

Fabian Glöckle (Apr 23 2019 at 19:30):

till the mk_mapp I assume

Simon Hudon (Apr 23 2019 at 19:30):

So if you put it before, it should print something

Fabian Glöckle (Apr 23 2019 at 19:31):

but you want trace information on app1?
then I can't put it above its definition

Simon Hudon (Apr 23 2019 at 19:32):

Right, my bad

Fabian Glöckle (Apr 23 2019 at 19:32):

till the mk_mapp I assume

the error is app_builder_exception, more information can be obtained using command set_option trace.app_builder true

Simon Hudon (Apr 23 2019 at 19:33):

I thought you had done that already

Fabian Glöckle (Apr 23 2019 at 19:33):

(which I already used when I pasted the error messages above)

Fabian Glöckle (Apr 23 2019 at 19:34):

yes

Fabian Glöckle (Apr 23 2019 at 19:36):

infer_type i₁ >>= trace btw gives has_add α as expected

Simon Hudon (Apr 23 2019 at 19:36):

Then try replacing app₁ ← mk_app has_x_x_name [α, i₁, x, y] with app₁ ← to_expr ``(@has_add.add %%α %%i₁ %%x %%y), to see what kind of error we can get

Fabian Glöckle (Apr 23 2019 at 19:41):

strangely, it worked to replace only app1in this way, leaving app2 as is

Fabian Glöckle (Apr 23 2019 at 19:41):

the trace of decl_bodyis λ (α β : Type) [i₁ : has_add α] [i₂ : has_add β] (f : α → β), ∀ {x y : α}, f (x + y) = f x + f y

Fabian Glöckle (Apr 23 2019 at 19:42):

however, lean still reports

failed to add declaration 'compatible' to environment, type has metavariables
  Π (α β : Type) [i₁ : has_add α] [i₂ : has_add β], (α  β)  Prop

Simon Hudon (Apr 23 2019 at 19:44):

The issue is with:

   has_x  mk_const has_x_name,
   has_x_x  mk_const has_x_x_name,

Simon Hudon (Apr 23 2019 at 19:45):

Try putting this somewhere above your proof:

set_option pp.universes true
#check @has_add.add

Simon Hudon (Apr 23 2019 at 19:45):

It will show you that has_add.add has one universe parameter u_1. Do you see that?

Fabian Glöckle (Apr 23 2019 at 19:49):

genius! here we go (has_add.{0} α =?= has_add.{?l_1} α) is the error from before I didn't understand

Johan Commelin (Apr 23 2019 at 19:50):

Too bad there isn't a universe-emoji...

Fabian Glöckle (Apr 23 2019 at 19:51):

:D :night_sky:

Fabian Glöckle (Apr 23 2019 at 19:55):

now the question is how to (dynamically) construct the has_addconstant with the right universe?

Mario Carneiro (Apr 23 2019 at 19:59):

use unify to determine the universe variables

Mario Carneiro (Apr 23 2019 at 20:10):

In this case, it seems like you are assuming that has_x already exists and has type has_[x] : Type u -> Type u. In that case, you can replace the mk_const invocations, which create a universe metavariable, with an explicit expr.const with universe u = 0 (replace the has_x and has_x_x lines with these):

   let has_x : expr := expr.const has_x_name [level.zero],
   let has_x_x : expr := expr.const has_x_x_name [level.zero],

Fabian Glöckle (Apr 23 2019 at 20:15):

Yes that is what I assume, and it works this way!

Fabian Glöckle (Apr 23 2019 at 20:15):

And all predefined has_... live in universe zero?

Mario Carneiro (Apr 23 2019 at 20:16):

no, they have type Type u -> Type u, so if you want alpha to have Type 0 then you have to set u = 0

Fabian Glöckle (Apr 23 2019 at 20:20):

how would I achieve the effect of α β : Type*?

Fabian Glöckle (Apr 23 2019 at 20:22):

mk_meta_univ?

Simon Hudon (Apr 23 2019 at 20:23):

(α β : Type*) is short for (α : Type u) (β : Type v) where u and v are not meta universes but universe parameters

Patrick Massot (Apr 23 2019 at 20:25):

Be careful that last message is unfortunately inaccurate, this is a well known bug

Fabian Glöckle (Apr 23 2019 at 20:26):

(α β : Type*) is short for (α : Type u) (β : Type v) where u and v are not meta universes but universe parameters

how can I declare universe parameters for my declaration?

Fabian Glöckle (Apr 23 2019 at 20:29):

like a normal function parameter?

Fabian Glöckle (Apr 23 2019 at 20:31):

meta def add_compatible_def (x : string) (u v : level): command ?

Fabian Glöckle (Apr 23 2019 at 20:35):

ah, there is level.param

Fabian Glöckle (Apr 23 2019 at 20:54):

and the level list in declaration.defn

Fabian Glöckle (Apr 26 2019 at 15:52):

Next questions :)
What does [app_builder] failed to create an 'mul_compatible'-application, failed to retrieve declarationmean?

Fabian Glöckle (Apr 26 2019 at 15:53):

My code:

def mul_compatible' {α β : Type} [has_mul α] [has_mul β] (f : α  β) : Prop :=
 {x0 x1 : α}, f (x0 * x1) = f x0 * f x1

lemma mul_compatible_id' {α : Type} [has_mul α]: mul_compatible' (id : α  α) := λ x y, rfl

meta def add_compatible_id_lemma : command :=
do has_mul  mk_const `has_mul,
   α  mk_local' `α binder_info.implicit (sort (level.succ level.zero)),
   i  mk_local' `i binder_info.inst_implicit (has_mul α),
   let ida : expr := const `id [level.succ level.zero],
   stmt  mk_app `mul_compatible' [α, α, i, i, ida α],  -- <-- error here
   let decl_type := expr.pis [α, i] stmt,
   x  mk_local' `x binder_info.default α,
   y  mk_local' `y binder_info.default α,
   let rf : expr := const `rfl [level.succ level.zero],
   mcapp  mk_app `mul_compatible' [α, α, i, i, ida α, x, y],
   let decl_body := expr.lambdas [α, i, x, y] (rf mcapp),
   add_decl $ declaration.thm `id_compatible [] decl_type (task.pure decl_body)

Fabian Glöckle (Apr 26 2019 at 16:00):

I'd like to generate the lemma mul_compatible_id'by code in a way such that I can later adapt it to other has_xsituations (hence no quasiquotations).

Fabian Glöckle (Apr 26 2019 at 16:01):

@Simon Hudon Do you have an idea what I did wrong?

Kevin Buzzard (Apr 26 2019 at 16:02):

@Fabian Glöckle do you have any comments on the univalence thread going on in the main chat?

Simon Hudon (Apr 26 2019 at 16:05):

That's an error given by mk_app or mk_mapp

Simon Hudon (Apr 26 2019 at 16:07):

There's an option that you can set to give more details about the application you're trying to build. The error message should mention which one

Fabian Glöckle (Apr 26 2019 at 16:14):

The error message is

app_builder_exception, more information can be obtained using command `set_option trace.app_builder true`

what I posted is already message from activating trace.app_builder

Edward Ayers (Apr 26 2019 at 16:14):

I got [app_builder] failed to create an 'mul_compatible''-application, failed to solve unification constraint for #4 argument (has_mul α =?= has_mul α)

Simon Hudon (Apr 26 2019 at 16:18):

try set_option pp.implicit true and set_option pp.universes true

Edward Ayers (Apr 26 2019 at 16:19):

[app_builder] failed to create an 'mul_compatible''-application, failed to solve unification constraint for #4 argument (has_mul.{0} α =?= has_mul.{?l_1} α)

Kevin Buzzard (Apr 26 2019 at 16:22):

I can solve that one

Kevin Buzzard (Apr 26 2019 at 16:23):

Maybe I should apply for a job at MS

Fabian Glöckle (Apr 26 2019 at 16:23):

I got [app_builder] failed to create an 'mul_compatible''-application, failed to solve unification constraint for #4 argument (has_mul α =?= has_mul α)

Sorry, you are right. Replacing the first line of the metacommand with

let has_mul : expr := const `has_mul [level.zero],

gives my error

Fabian Glöckle (Apr 26 2019 at 16:23):

Now we should have a minimal working example

Kevin Buzzard (Apr 26 2019 at 16:24):

Fabian, remember also to build a proper ZFC version of your tactic, which only allows Type and Prop for most basic definitions

Fabian Glöckle (Apr 26 2019 at 16:25):

?

Kevin Buzzard (Apr 26 2019 at 16:25):

You can't talk about terms in higher universes

Fabian Glöckle (Apr 26 2019 at 16:27):

:D no that was not the problem (though I still do not understand how to use universe parameters when building code)

Kevin Buzzard (Apr 26 2019 at 16:28):

Most mathematicians don't need those higher universes, so write a version that only works for things in Type and my mathematician's wager is that this never bothers us at all. I'm not really suggesting you do it, it's just that I am getting more and more weirded out by all this insistence on polymorphism when all it has done for me as a mathematician was cause me problems

Edward Ayers (Apr 26 2019 at 16:28):

Ah, the problem is that mk_app `mul_compatible' [α, α, i, i, ida α, x, y] is not allowed because mul_compatible' only accepts 5 arguments.

Edward Ayers (Apr 26 2019 at 16:30):

It's a shame Lean couldn't do that unification problem.

Fabian Glöckle (Apr 26 2019 at 16:30):

Oh right; i had thought it appeared in the first one :o

Fabian Glöckle (Apr 26 2019 at 16:30):

what would i do to specify the right type for the rfl (and do I need to?)

Edward Ayers (Apr 26 2019 at 16:37):

open tactic expr

def mul_compatible' {α β : Type} [has_mul α] [has_mul β] (f : α  β)  : Prop :=
 {x0 x1 : α}, f (x0 * x1) = f x0 * f x1

lemma mul_compatible_id' {α : Type} [has_mul α]: mul_compatible' (id : α  α) := λ x y, rfl

meta def add_compatible_id_lemma : command :=
do has_mul : expr  pure $ const `has_mul [level.zero],
   α  mk_local' `α binder_info.implicit (sort (level.succ level.zero)),
   i  mk_local' `i binder_info.inst_implicit (has_mul α),
   ida : expr  pure $ const `id [level.succ level.zero],
   stmt  mk_app `mul_compatible' [α, α, i, i, ida α],  -- <-- error here
  let decl_type := expr.pis [α, i] stmt,

   x  mk_local' `x binder_info.default α,
   y  mk_local' `y binder_info.default α,
   xy  mk_app `has_mul.mul [i, x, y],
   rf  mk_app `rfl [xy],
   let decl_body := expr.lambdas [α, i, x, y] (rf),
   add_decl $ declaration.thm `id_compatible [] decl_type (task.pure decl_body)

-- set_option trace.app_builder true
-- set_option pp.all true
-- set_option formatter.hide_full_terms false
run_cmd do {
  add_compatible_id_lemma
}

Edward Ayers (Apr 26 2019 at 16:38):

#check id_compatible works for me.

Fabian Glöckle (Apr 26 2019 at 16:44):

Oh great, thanks
It turns out these weren't issues with metaprogramming but with understanding the rflproof :D

Fabian Glöckle (Apr 26 2019 at 16:48):

I really appreciate the helpful atmosphere here, thanks again!!

Edward Ayers (Apr 26 2019 at 16:48):

You can get Lean to do most of the work:

open tactic expr

def mul_compatible' {α β : Type} [has_mul α] [has_mul β] (f : α  β)  : Prop :=
 {x0 x1 : α}, f (x0 * x1) = f x0 * f x1

lemma mul_compatible_id' {α : Type} [has_mul α]: mul_compatible' (id : α  α) := λ x y, rfl

meta def add_compatible_id_lemma : command :=
do
   target  to_expr ```(Π {α : Type} [has_mul α], mul_compatible' (id : α  α)),
   g  mk_mvar,
   gs  get_goals,
   set_goals [g],
   change target,
   intro_lst [`α, `i, `x,`y], -- or just `intron 4`
   reflexivity,
   set_goals gs,
   g  instantiate_mvars g,
   add_decl $ declaration.thm `id_compatible [] target (task.pure g)


run_cmd do {
  add_compatible_id_lemma
}

#check id_compatible

Edward Ayers (Apr 26 2019 at 16:51):

Can anyone golf this down further?

Simon Hudon (Apr 26 2019 at 19:24):

Try:

meta def add_compatible_id_lemma : command :=
do target  to_expr ```(Π {α : Type} [has_mul α], mul_compatible' (id : α  α)),
   (_,g)  solve_aux target $ do
   { intro_lst [`α, `i, `x,`y], -- or just `intron 4`
     reflexivity },
   g  instantiate_mvars g,
   add_decl $ declaration.thm `id_compatible [] target (task.pure g)

Mario Carneiro (Apr 26 2019 at 20:10):

meta def add_compatible_id_lemma : command :=
do
   target  to_expr ```(Π {α : Type} [has_mul α], mul_compatible' (id : α  α)),
   g  to_expr ```(λ α i x y, rfl : %%target),
   add_decl $ declaration.thm `id_compatible [] target (task.pure g)

Johan Commelin (May 04 2019 at 08:56):

Can your tactics also add docstrings to the new declarations? @Mario Carneiro Is such a thing possible?

Mario Carneiro (May 04 2019 at 08:56):

yes, you can programmatically add docstrings to decls

Mario Carneiro (May 04 2019 at 08:56):

alias does this

Fabian Glöckle (May 06 2019 at 16:14):

thank you three for the immediate golfing instinct by the way
my real code is for generic has_xyz though where i couldn't use quotations so easily
any ideas on how to improve this? https://github.com/faabian/mathlib/blob/meta/meta.lean

Edward Ayers (May 06 2019 at 19:33):

Maybe something like this. It's not much shorter but you don't have to worry about universes anywhere.

meta def add_compatible_def (x : string): command :=
do let T : expr := expr.sort $ level.succ $ level.param `v,
   let has_x_name := mk_simple_name ("has_" ++ x),
   let has_x_x_name := has_x_name <.> x,
   has_x  mk_const has_x_name,
   t  mk_const has_x_x_name >>= infer_type,
   ((ty :: cl :: domain), codomain)  mk_local_pis t,
   let arity := domain.length,
   let target_self := codomain =  ty,
   target_prop  is_prop codomain,
   decl_type  to_expr ```(Π {α β :%%T} [%%has_x α] [%%has_x β] (f : α  β), Prop),
   (_,decl_body)  solve_aux decl_type (do
     [α,β,i₁,i₂,f]  intros,
     vars  list.mmap (λ n, do
        refine_forall (mk_simple_name ("x" ++ to_string n)) α
     ) $ list.range arity,
     app₁  mk_app has_x_x_name $ vars,
     app₂  mk_app has_x_x_name $ list.map (expr.app f) vars,
     body_main  if target_self then to_expr ``(%%f (%%app₁) = %%app₂)
                  else (if target_prop then to_expr ``(%%app₁  %%app₂)
                        else to_expr ``(%%app₁ = %%app₂)),
     exact body_main
   ),
   decl_body  instantiate_mvars decl_body,
   let decl_name := mk_simple_name (x ++ "_compatible"),
   add_decl $ mk_definition decl_name (collect_univ_params decl_type) decl_type decl_body  -- universes here
   -- todo: allow both → and ↔ for Prop-valued?

run_cmd add_compatible_def "mul"
run_cmd add_compatible_def "ternary"
run_cmd add_compatible_def "lt"
run_cmd add_compatible_def "to_string"
#print mul_compatible
#print ternary_compatible
#print lt_compatible
#print to_string_compatible

Edward Ayers (May 06 2019 at 19:37):

I defined refine_forall as:

/-- Take a goal `⊢ Prop` and fill with a `pi` to get a new goal `n : type ⊢ Prop` -/
meta def refine_forall (n : name) (type : expr) : tactic expr := do
    f_type  to_expr ```(%%type  Prop),
    f  mk_meta_var f_type,
    tactic.exact (expr.pi n binder_info.default type (expr.app f (expr.var 0))),
    set_goals [f],
    intro n

Edward Ayers (May 06 2019 at 19:39):

Your code looks fine. If you are having to explicitly write out universe terms then Lean probably provides a tactic that means you don't have to.

Edward Ayers (May 06 2019 at 19:57):

I prefer always having local variables held in the tactic_state's context rather than using mk_local and friends. This is because you don't have to worry about pretty names and unique names etc. But there is nothing wrong with the mk_local way.

Edward Ayers (May 06 2019 at 20:11):

There should be a way to replace count_vars, arrow_list, with tactic.mk_local_pis, tactic.get_pi_arity and so on. They are in /library/init/meta/tactic.lean and expr.lean.

Edward Ayers (May 06 2019 at 20:51):

This has been a good exercise for me. Here are some problems that I had:
- If I write to_expr ```(Π {α β}, ... it makes a new universe metavariable. Then I get told off for trying to make a decl with a metavariable in it. I couldn't find a nice way of telling the tactic_state to turn all remaining universe metas in to universe parameters instead. Am I not seeing the tactic?
- refine_forall (and refine_pi) is a utility function that I use a lot and find really useful. Is there a version of this in mathlib or core?
- Is it better to use mk_local_pis and expr.pis or to wrap things in tactics?

Fabian Glöckle (May 28 2019 at 11:48):

Thanks @Edward Ayers for your tricks, that solved my universe issues!

Edward Ayers (May 28 2019 at 11:48):

No problem!


Last updated: Dec 20 2023 at 11:08 UTC