Zulip Chat Archive

Stream: general

Topic: get the "visible" head of an expression


Scott Morrison (Mar 11 2021 at 23:19):

I would like a function that takes an expr, and returns to me the "head", including implicit arguments.

Thus @rfl X should stay as @rfl X, nat.factorial 7 should produce nat.factorial, and 3 + 7 should produce @has_add.add nat nat.has_add.

Scott Morrison (Mar 11 2021 at 23:19):

Does that make sense? Do we already have it?

Scott Morrison (Mar 11 2021 at 23:20):

There is expr.get_app_fn, which gets the very topmost head of the app. (But this turns @rfl X into just @rfl, etc.)

Scott Morrison (Mar 11 2021 at 23:25):

I guess if it existed it would be in src/meta/expr.lean, and there doesn't seem to be anything like this.

Scott Morrison (Mar 11 2021 at 23:30):

I had hoped that I could achieve this using pattern matching, e.g. something like

match e with
| `(%%f %%x) := return f
| _ := sorry
end

but this just gives me a function expected at error on the %%f.

Scott Morrison (Mar 12 2021 at 00:28):

meta def app_implicits : expr  list expr  tactic expr
| f [] := return f
| f (x :: xs) := do
  ty  infer_type f,
  match binding_info ty with
  | binder_info.default := return f
  | _ := app_implicits (f x) xs
  end

meta def get_app_fn_with_implicits (e : expr) : tactic expr :=
do
  let (f, args) := e.get_app_fn_args,
  app_implicits f args

seems to do it.

Mario Carneiro (Mar 12 2021 at 02:38):

Here's a version that avoids multiple calls to infer_type:

import tactic.core
open tactic expr

meta def app_implicits : expr  list expr  expr  expr
| f (x :: xs) (pi _ binder_info.default _ ty) := f
| f (x :: xs) (pi _ _ _ ty) := app_implicits (f x) xs ty
| f _ _ := f

meta def get_app_fn_with_implicits (e : expr) : tactic expr :=
let (f, args) := e.get_app_fn_args in
app_implicits f args <$> infer_type f

Scott Morrison (Mar 12 2021 at 10:47):

Thanks!


Last updated: Dec 20 2023 at 11:08 UTC