Zulip Chat Archive

Stream: lean4

Topic: adding definitions


Patrick Massot (Aug 21 2022 at 22:05):

What is the simplest way in CommandElabM to create a new definition using a object that we already have? For instance assume my tactic state is

arr : Array Nat
 CommandElabM PUnit

What is the simplest way to add to the current environment a definition with name foo, type Array Nat and value arr? I know I can write

  let typ : Expr := mkApp (mkConst ``Array) (mkConst ``Nat)
  let val : Expr := sorry
  let decl : Declaration := Declaration.defnDecl {name := `foo, levelParams := [], type := typ, value := val, hints := ReducibilityHints.opaque, safety := DefinitionSafety.safe}
  addAndCompile decl

but it seems very complicated and I don't really know how to construct the val expression. I could also try to create some Syntax and use elabCommand but it seems even more tortuous.

Arthur Paulino (Aug 21 2022 at 22:58):

I could be wrong, but I think you need to build the value expression

Arthur Paulino (Aug 21 2022 at 22:59):

(I'm not sure if you don't want a solution that involves building the value expression of if you just don't know how to)

Arthur Paulino (Aug 21 2022 at 23:08):

To build the value expression, you can use mkNatLit to build a List Expr from arr, mkListLit to build an expression that represents the List Nat and mkApp to build the expression that represents the Array Nat

Patrick Massot (Aug 22 2022 at 07:18):

Thanks Arthur. I was really hoping for a much simpler way. Basically I'd like a (monadic) function creating an Expr from a local declaration in my "programming state" (I don't really know how to call what the info view is showing while I'm programming in do notation).

Patrick Massot (Aug 22 2022 at 07:18):

But maybe those difficulties show that I'm following a completely wrong path.

Gabriel Ebner (Aug 22 2022 at 08:47):

elabCommand ( `(def foo : Array Nat := $(quote arr)))

Note that this will add a definition with the (inaccessible) declaration name (← `(foo)).getId.

Gabriel Ebner (Aug 22 2022 at 08:51):

If you want to go with addAndCompile directly, you can do:

addAndCompile <| .defnDecl {
  name := `foo
  levelParams := []
  type := toTypeExpr (Array Nat)
  value := toExpr arr
  hints := .regular (getMaxHeight ( getEnv) (toExpr arr) + 1)
  safety := .safe
}

Patrick Massot (Aug 22 2022 at 09:01):

Thanks Gabriel!

Patrick Massot (Aug 22 2022 at 09:02):

Gabriel Ebner said:

Note that this will add a definition with the (inaccessible) declaration name (← `(foo)).getId.

Unless I disable hygiene, right?

Gabriel Ebner (Aug 22 2022 at 09:22):

I would never suggest to disable hygiene. If you want a non-hygienic name for the definition I'd do:

elabCommand ( def $(mkIdent `foo):ident : Array Nat := $(quote arr))

Patrick Massot (Aug 22 2022 at 09:30):

Sorry about the heretic suggestion and thanks for telling me how to redeem myself.

Arthur Paulino (Aug 22 2022 at 11:38):

Oh, toExpr and toTypeExpr for the rescue! I didn't know those

James Gallicchio (Aug 22 2022 at 16:20):

Definitely would be worth including somewhere in the metaprogramming book, I had the exact question as Patrick earlier this week and resorted to manually reconstructing the syntax

Arthur Paulino (Aug 22 2022 at 16:28):

Good call. Added as an issue

Patrick Massot (Aug 22 2022 at 18:15):

I'm back to Lean and none of Gabriel's solutions works in my real use case :sad: There is no miracle, quote, toExpr and toTypeExpr all require instances.

Gabriel Ebner (Aug 22 2022 at 18:16):

Then you should post your real use case. :smile:

Patrick Massot (Aug 22 2022 at 18:17):

And no luck with hoping for deriving miracles.

Patrick Massot (Aug 22 2022 at 18:18):

In the real case Nat is replaced with a home-made structure.

Patrick Massot (Aug 22 2022 at 18:18):

However the fields of that structure are either Name or String so I guess defining the missing instances shouldn't be too hard

Patrick Massot (Aug 22 2022 at 18:26):

I managed to create the Quote instance!

Patrick Massot (Aug 22 2022 at 18:27):

I don't know how the deriving magic works but it looks like what I did is easy to automate to get a Quote instance for a structure where all fields have Quote instances.

Patrick Massot (Aug 23 2022 at 20:09):

I have a dual question. Inside a TermElabM computation I want to get access to an object that have been declared previously. Am I meant to use docs4#Lean.Environment.find? and then docs4#ConstantInfo.value! and then docs4#Lean.Meta.evalExpr or is there a more direct route?

Patrick Massot (Aug 23 2022 at 20:10):

The Zulip linkfier doesn't like declaration names ending in punctuation marks :sad:

Mario Carneiro (Aug 23 2022 at 20:33):

If you just want the expr then ((<- getEnv).find? name).get!.value! will do the trick

Patrick Massot (Aug 23 2022 at 20:34):

I know, but I want the object, that's why I'm asking whether I should use evalExpr. It sounds a bit expensive to to this while Lean already did that work at declaration time.

Mario Carneiro (Aug 23 2022 at 20:34):

evalConst is a bit easier than evalExpr for this case

Mario Carneiro (Aug 23 2022 at 20:35):

(<- getEnv).evalConst A (<- getOptions) name

Sebastian Ullrich (Aug 23 2022 at 20:35):

A definition, even with zero parameters, is not immediately evaluated to an object at declaration time

Patrick Massot (Aug 23 2022 at 20:36):

Does it mean it's evaluated every time we use it?

Sebastian Ullrich (Aug 23 2022 at 20:41):

In compiled code, it is evaluated once. In interpreted code, it is currently evaluated once per interpreter invocation (i.e. if your interpreted tactic calls evalConst multiple times on the same declaration, it should only be evaluated once I think).

Patrick Massot (Aug 23 2022 at 23:10):

It feels a but weird that I need to add unsafe everywhere because I want to access declared objects (both evalExpr and evalConst are unsafe).

Mario Carneiro (Aug 23 2022 at 23:32):

The operation is fundamentally unsafe, since nothing prevents you from passing the wrong type to evalExpr

Mario Carneiro (Aug 23 2022 at 23:33):

You can use Mathlib.Util.TermUnsafe to make it a bit more ergonomic to call unsafe functions

Reid Barton (Nov 18 2022 at 20:47):

Now known as Std.Util.TermUnsafe.


Last updated: Dec 20 2023 at 11:08 UTC