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: May 02 2025 at 03:31 UTC