Zulip Chat Archive

Stream: new members

Topic: has_to_pexpr and has_reflect for a function


Angela Li (Jan 01 2021 at 20:21):

Hello! For Fifteen, I'm trying to write a tactic to close the goal when you reach the goal position. Here is the project leanproject get SnobbyDragon/leanfifteen.
My tactic (called finish_game in the file fifteentactics.lean) is supposed to be a macro for the easy_cheesy example in the file play.lean

meta def finish_game : tactic unit :=
do { p  get_position,
     «have» `H ``(%%p.map = goal_position.map) ``(by dec_trivial), --this line doesn't work
     tactic.skip
} <|> tactic.fail "we are not done !"

example : game easy_cheesy :=
begin
  slide_tile dd, --excluding this line
  have H : (slide dd dc easy_cheesy).map = goal_position.map := by exact dec_trivial,
  have H' : (slide dd dc easy_cheesy) = goal_position := by tauto,
  rw H',
  apply can_slide_to.self goal_position,
end

I'm not too sure how to do have since it's complaining about has_to_pexpr, so I tried reflecting, but it didn't like @[derive has_reflect] for a function. This would fail (in file fifteen.lean):

@[derive [decidable_eq, has_reflect]]
structure position :=
(map : tile  fin 16)
-- (bij : function.bijective map)

Is there a way I can make it has_reflect? Or is there a better way to approach this?
Any insight/feedback is appreciated!
Thanks!

Mario Carneiro (Jan 01 2021 at 20:22):

what does get_position return? What does the tactic state look like just before finish_game?

Mario Carneiro (Jan 01 2021 at 20:23):

You probably don't want to be reflecting anything

Angela Li (Jan 01 2021 at 20:23):

get_position returns tactic position

Mario Carneiro (Jan 01 2021 at 20:25):

See why do you need that? You should keep the positions out of the tactic, and then you don't need reflect to turn it back into an expr. It should be a tactic expr

Mario Carneiro (Jan 01 2021 at 20:25):

how is it implemented

Angela Li (Jan 01 2021 at 20:26):

oh wait that makes more sense.

meta def get_position : tactic position :=
do { `(can_slide_to %%p₁ %%p₂)  tactic.target,
     p  (eval_expr position) p₁,
     return p
} <|> get_start_position

I think i was just using it for other things

Angela Li (Jan 01 2021 at 20:26):

but I'll just not use this in what im trying to do

Mario Carneiro (Jan 01 2021 at 20:26):

don't do eval_expr

Mario Carneiro (Jan 01 2021 at 20:26):

just return p1

Mario Carneiro (Jan 01 2021 at 20:30):

I downloaded your project but you are using begin [fifteen_tactic'] end and it complains that the fifteen_tactic' tactic class doesn't exist, which is true

Angela Li (Jan 01 2021 at 20:31):

oh wait i forgot to push a file sorry ill do that now

Angela Li (Jan 01 2021 at 20:31):

okay pushed!

Mario Carneiro (Jan 01 2021 at 20:32):

yeehaw indeed

Mario Carneiro (Jan 01 2021 at 20:34):

So without using finish_game, just using the underlying tactics manually, what would a completed game look like?

Mario Carneiro (Jan 01 2021 at 20:34):

I tried

example : game easy_cheesy :=
begin
  slide_tile dd,
  exact dec_trivial,
end

but that doesn't work

Angela Li (Jan 01 2021 at 20:35):

example : game easy_cheesy :=
begin
  slide_tile dd,
  have H : (slide dd dc easy_cheesy).map = goal_position.map := by exact dec_trivial,
  have H' : (slide dd dc easy_cheesy) = goal_position := by tauto,
  rw H',
  apply can_slide_to.self goal_position,
end

I think this should end it. I'm not sure why it's so complicated

Angela Li (Jan 01 2021 at 20:35):

Probably with how I defined the structure position ? It only has a function in it bc I commented out the bijective part since it made things hard

Mario Carneiro (Jan 01 2021 at 20:39):

it looks like derive decidable_eq is not making a good instance. Try this instead:

@[ext] structure position :=
(map : tile  fin 16)

instance : decidable_eq position :=
λ a b, decidable_of_iff' _ (position.ext_iff _ _)

Angela Li (Jan 01 2021 at 20:40):

Cool thanks!

Mario Carneiro (Jan 01 2021 at 20:42):

then you can reduce the original proof to

lemma can_slide_to.of_eq :  {p₁ p₂ : position} (h : p₁ = p₂), can_slide_to p₁ p₂
| p _ rfl := can_slide_to.self p

example : game easy_cheesy :=
begin
  slide_tile dd,
  exact can_slide_to.of_eq dec_trivial,
end

Mario Carneiro (Jan 01 2021 at 20:45):

And then your tactic reduces to:

meta def finish_game : tactic unit :=
do { applyc ``can_slide_to.of_eq,
     tactic.exact_dec_trivial
} <|> tactic.fail "we are not done !"

example : game easy_cheesy :=
begin
  slide_tile dd,
  finish_game
end

Angela Li (Jan 01 2021 at 20:46):

Is it better to do that than stuff like `[exact can_slide_to.of_eq dec_trivial]

Mario Carneiro (Jan 01 2021 at 20:49):

It's more flexible, and a bit faster. The tactic quoting syntax is pretty limited as you saw with that have proof

Mario Carneiro (Jan 01 2021 at 20:50):

In this case you want as much to be done in a theorem as you can, and then just call the dec_trivial tactic to do the part that depends on the actual goal

Mario Carneiro (Jan 01 2021 at 20:50):

You can also automatically finish every proof in your custom state with this as a "closer":

  meta instance : interactive.executor fifteen_tactic' :=
  { config_type := unit,
    execute_with := λ n tac, tac >> fifteentactics.finish_game
  }

example : game easy_cheesy :=
begin [fifteen_tactic']
  slide_tile dd,
end

Angela Li (Jan 01 2021 at 20:51):

Ooo that's cool thanks so much!

Mario Carneiro (Jan 01 2021 at 20:51):

You probably need some special handling with the widget stuff if you want to show the goal in case of errors

Angela Li (Jan 01 2021 at 20:53):

True... although I haven't managed to make an error through clicking yet (at least since I disabled clicking on tiles not next to the hole) but I wouldn't count on it :eyes:


Last updated: Dec 20 2023 at 11:08 UTC