In Coq, I am trying to formalize the notion of a finite or infinite sequence, e.g. of natural numbers: call it a run
, and call pos
a finite run.
I think I cannot use plain stdlib Stream
s since I have a possible base case: the first consequence, compared to Stream
, is that my run_hd
, run_tl
, etc., up to run_nth
must return option
s since I can have empty run
s, but I guess that is not a problem.
The actual problem is that eventually I do not know how to define a usable predicate and/or computable function to determine/state/distinguish between finite and infinite run
s.
Here is some minimal code that I hope is representative enough, where I am trying to have structural sub-typing, but I just cannot get to the bottom of it:
CoInductive run : Set :=
| RunO : run (* base for finite runs *)
| RunS : nat -> run -> run.
Inductive pos : Set := (* structurally a finite run *)
| PosO : pos
| PosS : nat -> pos -> pos.
Definition IsFinRun (r : run) : Prop.
Admitted. (* HOW? *)
Coercion pos_to_run (p : pos) : run.
Admitted. (* easy *)
Coercion run_to_pos (r : run) : IsFinRun r -> pos.
Abort. (* HOW? *)
For example, among many variations, I have tried:
Definition IsFinRun (r : run) : Prop :=
exists n : nat, forall m : nat,
m <= n <-> run_nth m r <> None.
Coercion run_to_pos (r : run) :
IsFinRun r -> pos.
Proof. (* in proof mode to explore it *)
unfold IsFinRun.
intros H.
destruct H. (* ERROR:
Case analysis on sort Set is not allowed
for inductive definition ex. *)
(The same error, just on sort Type, happens if I replace Set with Type everywhere. In fact, I do not understand why that error at all, given n
is a nat
.)
(I have tried to keep the whole thing as brief as possible, but I can post more/full code if necessary, just please let me know.)
What am I missing? In particular, how could I fix/complete the code up to run_to_pos
? Thanks in advance for any help or insight.
pos_to_run
, so you could define it this way (and this is a proposition becausepos_to_run
is an embedding, so you can represent this with a $\Sigma$-type). If you want a decidable criterion, then you'd need something like a coproduct of (inductive) lists and streams. $\endgroup$Definition IsFinRun (r : run) : Set := {p : pos | r = pos_to_run p}.
-- OTOH, I had thought about the coproduct, but then I thought, maybe wrongly, that it would be less elegant than structural subtyping as well as less faithful to the informal progression and notions... anyway, as for decidability, I'd have thought working inSet
was the critical factor: I am missing the distinction you are making in that sense. $\endgroup$Bool
. $\endgroup$run
s". If you use your definition ofrun
then you can only semidecide whether a run is finite. $\endgroup$