Zulip Chat Archive

Stream: lean4

Topic: Default tactic argument?


Avi Craimer (Nov 05 2023 at 14:55):

When I'm writing a type that does a simple guard check using a proof of a proposition as an argument, is there a way to make the proof argument implicit and provide a default tactic.

Here is the example I'm working on.

inductive Context: List String -> Type where
| empty : Context []
| extend: (ctx: (Context names)) -> (name: String) ->
  (_: names.contains name = false) -> Context (name::names)

def cat := Context.extend Context.empty "cat" (by decide)

def catdog := Context.extend cat  "dog" (by decide)

def catdogcat := Context.extend catdog "cat" (by decide)
-- Can't add cat again, the tactic will fail.

This works fine, but I have to pass the argument (by decide) explicitly every time I use Context.extend. I tried making the third argument implicit like this:

inductive Context: List String -> Type where
| empty : Context []
| extend: (ctx: (Context names)) -> (name: String) ->
  {_: names.contains name = false} -> Context (name::names)

but I get the error:

don't know how to synthesize implicit argument
  @Context.extend [] Context.empty "cat" ?m.3624
context:
 List.contains [] "cat" = false

Since this is always a decidable problem is there a way to give a hint to the compiler to use decide to synthesize the implicit argument?

Marcus Rossel (Nov 05 2023 at 15:24):

You can add a default argument for the proof parameter of the extend constructor:

inductive Context: List String -> Type where
| empty : Context []
| extend: (ctx: (Context names)) -> (name: String) ->
  (_: names.contains name = false := by decide) -> Context (name::names)

def cat := Context.extend Context.empty "cat"

def catdog := Context.extend cat  "dog"

def catdogcat := Context.extend catdog "cat"
-- Can't add cat again, the tactic will fail.

Avi Craimer (Nov 05 2023 at 16:18):

Thanks @Marcus Rossel I didn't know about default arguments in Lean!

Avi Craimer (Nov 05 2023 at 16:20):

As a follow up to this.

How do I define Repr. When I use the deriving Repr it fails, I guess because it can't print the proof term. How do I tell it to ignore the proof term when printing the Context term?

Mario Carneiro (Nov 05 2023 at 16:22):

right now you have to write Repr instances manually if deriving Repr fails

Mario Carneiro (Nov 05 2023 at 16:22):

instance (l) : Repr (Context l) := ...

Avi Craimer (Nov 06 2023 at 00:46):

--

Avi Craimer (Nov 06 2023 at 00:48):

I realized a simpler way to to the context would be like this:

abbrev  Context := { list: List String // list = list.eraseDups }

But then I don't know how to prove that if a list meets the property to be a context, then the tail of that list is also a Context.

i.e.,

def tail (ctx: Context): Context :=
  match ctx with
   |   [], _  =>   [], by decide
   |   x::xs, p  =>  xs, sorry 

Clearly, I need to do something with p but I'm not sure what.

Avi Craimer (Nov 06 2023 at 00:52):

The other thing I'm struggling with is how to write a fromList function. I want to take a list, apply eraseDups and then produce a Context. It seems obvious, but I can figure out how to prove that list.eraseDups = list.eraseDups.eraseDups.

Marcus Rossel (Nov 06 2023 at 11:42):

This might not be what you want, but if you're ok with using Lean's Std library you can use docs#List.Nodup. Then you'll probably find the appropriate lemmas like docs#List.nodup_cons. And if you're ok with using Mathlib you could even go for docs#Finset.

Avi Craimer (Nov 06 2023 at 15:45):

@Marcus Rossel Thanks Marcus. As I'm still very new to using Lean, I haven't figured out how to import stuff from Mathlib. Do I need to create a project folder to do so? Up until now I've just been working in a single file using whatever is in Prelude.

Ruben Van de Velde (Nov 06 2023 at 15:52):

Yes, you need to create a project that depends on mathlib

Mario Carneiro (Nov 06 2023 at 15:53):

lake init myproj math


Last updated: Dec 20 2023 at 11:08 UTC