I'm trying to fully understand `ssreflect`

views.

Looking at https://coq.inria.fr/distrib/current/refman/proof-engine/ssreflect-proof-language.html#id16

I do not understand why the following example works:

```
Goal forall x, x = 1 -> x = 2 -> 7 = 8.
Proof.
move=> + + + /ltac:(exfalso).
(* new Goal is forall x : nat, x = 1 -> x = 2 -> False *)
```

It is quite common (for me) to temporarily introduce some arguments (without naming them explicitly), then apply a lemma or tactic, then revert the arguments.

This seems to be covered by views, but I do not understand how. Also , I find `move=> H1 H2 H3; exfalso; move: H1 H2 H3.`

with unnecessary names dissatisfactory.

Is there more documentation on `ssreflect`

views that could explain the above example?

Maybe these workshop slides? https://staff.aist.go.jp/reynald.affeldt/coq2019/coqws2019-martindorel-tassi-slides.pdf (see slide 7)

`=> +++ /ltac:(code)`

is *equivalent* to `move=> H1 H2 H3; exfalso; move: H1 H2 H3.`

for well chosen names `H1`

.. `H3`

.

The `+`

introduces a temporary assumption, which is then moved down to the goal at the very end of the intro pattern.

Does the explanation of `+`

answer your question?

Does the explanation of

`+`

answer your question?

I understand `+`

. I cannot find documentation on `move=> /ltac:(code)`

.

Most disturbingly, it feels like `move=> /something`

requires the goal to have at least one top argument (the documentation says `It first introduces top.`

). However, in the case of `move=> /ltac:(exfalso)`

it can be executed on any goal (e.g. `7 = 8`

in the above example).

`ltac:`

is documented here: https://coq.inria.fr/refman/proof-engine/ltac.html (not sure it is the best place to look at)

Maybe these workshop slides? https://staff.aist.go.jp/reynald.affeldt/coq2019/coqws2019-martindorel-tassi-slides.pdf (see slide 7)

Slide 7 exactly matches my understanding. However, it does not apply to the above example, as in the above example there is no assumption to be interpreted by the view.

You are right, I cannot find the doc either. I'll summarize here and open a bugreport later.

Views are terms as in `/t`

and they need to be applied to something, which is the top of the stack (the first assumption of the goal). For example if `t : A -> B`

it needs an `A`

to operate on, which is the top of the stack.

You can do many things with a term, but not everything. Hence the possibility to plug a custom ltac piece of code in there. The ltac piece of code does not need an assumption to be useful, hence the discrepancy (it can introduce the top of the stack itself if it needs something to operate on).

See https://github.com/math-comp/math-comp/pull/599 for some use cases. `[dup]`

operates on the top of the stack. `[swap]`

needs 2 slots. Some other examples in the PR linked by that one, such as `[! inE]`

, needs 0 stack slots to be useful.

See https://github.com/math-comp/math-comp/pull/599 for some use cases

That is an interesting PR and covers many of my use cases .

May I suggest to ping the author then ;-) The PR is almost ready to be merged

A +1 would motivate him I guess

It did, I opened coq/coq#13317

By the way, isn't there good design space for `move=> /lemma`

in case the current goal has no top assumption?

E.g. it could be a synonym for `apply /lemma`

. This would enable e.g. `move=> ++ /lemma1 => /lemma2 => * /lemma3`

instead of `move=> H1 H1; apply /lemma1; move: H1 H2 => /lemma2 *; apply /lemma3`

.

at least I rely on the distinction when reading — but can’t your example be written as `move=> H1 /lemma2 H2; apply /lemma1 /lemma3`

?

“the distinction” = the distinction between `move => /lemma`

and `apply /lemma`

— I know the former applies to an assumption.

If you don’t want to specify, I think you can `rewrite`

with bi-implications. It does become annoying that you can’t rewrite by normal implications, but that’d probably be a bad idea

you can’t rewrite by normal implications, but that’d probably be a bad idea

Unidirectional lemma rewriting definitely feels wrong.

“the distinction” = the distinction between

`move => /lemma`

and`apply /lemma`

— I know the former applies to an assumption.

As the previous discussion has shown, this is already not the case for `/ltac:(code)`

and has its benefits for more fluent bookkeeping.

Still, I agree that such ambiguity could make the proof less maintainable as the result depends on the current number of arguments in the Goal.

I'm just wondering whether there is some more uniform and fluent principles to the bookkeeping part of ssr.

you could define your own ltac in term for `apply/`

, I cannot make it work for `apply/`

but it works for `apply:`

(@Enrico Tassi is there a bug?)

```
Notation "'[apply:' x ']'" := (ltac:(apply: x))
(at level 0, x at level 200, only parsing) : ssripat_scope.
Notation "'[apply/' x ']'" := (ltac:(apply/ x))
(at level 0, x at level 200, only parsing) : ssripat_scope.
Lemma test A B C D
(lemma1 : B -> C) (lemma2 : D -> A -> B -> C) (lemma3 : True -> B) :
A -> B -> C.
Proof. Fail by move=> + + /[apply/lemma1] -/lemma2 * /[apply/lemma3]. Restart.
Proof. by move=> + + /[apply: lemma1] -/lemma2 * /[apply: lemma3]. Qed.
```

Last updated: Jun 18 2024 at 08:01 UTC