Zulip Chat Archive

Stream: general

Topic: Type inference


Bolton Bailey (Nov 21 2022 at 12:42):

With this code

import data.mv_polynomial.basic

lemma mwe {F : Type} [field F] {cols rows : }
  (constraint : mv_polynomial (fin cols × fin rows) F)
  (trace : fin cols -> fin rows -> F) :
  mv_polynomial.eval (λ row_col , trace (row_col.fst) (row_col.snd)) constraint = 0
  := sorry

I get the following tooltips on row_col:

row_col : fin cols × fin rows

and then

invalid field notation, type is not of the form (C ...) where C is a constant
  row_col
has type
  ?m_1Lean

And the code

import data.mv_polynomial.basic

lemma mwe {F : Type} [field F] {cols rows : }
  (constraint : mv_polynomial (fin cols × fin rows) F)
  (trace : fin cols -> fin rows -> F) :
  mv_polynomial.eval (λ row_col : (fin cols × fin rows), trace (row_col.fst) (row_col.snd)) constraint = 0
  := sorry

works fine. Why is VSCode smart enough to tell me the type of row_col, but Lean apparently needs to be told it?

Kyle Miller (Nov 21 2022 at 12:53):

I'm going to guess it has to do with elaboration order and the fact that lean will continue elaborating despite errors. It's able to eventually figure out that row_col has the type it does because it comes from the constraint argument, but Lean visits arguments to functions in left-to-right order, so when it's handling dot/field notation it does not yet know the type of row_col.

Kyle Miller (Nov 21 2022 at 12:55):

Flipping the argument order fixes it:

noncomputable
def mv_polynomial.eval' {R : Type*} {σ : Type*} [comm_semiring R] (p : mv_polynomial σ R) (f : σ  R) : R :=
mv_polynomial.eval f p

lemma mwe {F : Type} [field F] {cols rows : }
  (constraint : mv_polynomial (fin cols × fin rows) F)
  (trace : fin cols -> fin rows -> F) :
  mv_polynomial.eval' constraint (λ row_col , trace (row_col.fst) (row_col.snd)) = 0
  := sorry

Eric Wieser (Nov 21 2022 at 13:03):

Inserting a by exact might also change the elaboration order to the one that works

Kyle Miller (Nov 21 2022 at 13:08):

Not here, lambda expression bodies process all pending tactics

Eric Wieser (Nov 21 2022 at 13:09):

Works for me:

import data.mv_polynomial

lemma mwe {F : Type} [field F] {cols rows : }
  (constraint : mv_polynomial (fin cols × fin rows) F)
  (trace : fin cols -> fin rows -> F) :
  mv_polynomial.eval (by exact λ row_col , trace (row_col.fst) (row_col.snd)) constraint = 0
  := sorry

Kyle Miller (Nov 21 2022 at 14:24):

Oh, I thought you meant inside the lambda. Your example working is consistent with the theory that elaboration of lambda bodies triggers the processing of pending tactic blocks.

Eric Wieser (Nov 21 2022 at 14:28):

I don't think it gives any evidence for that theory, the lambda doesn't even exist until the tactic block is execute there.

Kyle Miller (Nov 21 2022 at 14:51):

This is what I'm referring to: https://github.com/leanprover-community/lean/blob/master/src/frontends/lean/elaborator.cpp#L3404

Kyle Miller (Nov 21 2022 at 14:52):

The previous five lines visit the body of the lambda, and synthesize() is for handling a number of deferred things, including pending tactics.


Last updated: Dec 20 2023 at 11:08 UTC