Я пытаюсь определить простой язык на основе стека в Coq. На данный момент набор инструкций содержит push
, который выдвигает nat
, и инструкцию pop
, которая высовывает единицу. Идея состоит в том, что программы типизированы зависимо; Prog 2
- это программа, которая оставляет два элемента в стеке после выполнения.
Это реализовано с помощью этой простой программы:
Require Import Coq.Vectors.VectorDef.
Inductive Prog : nat -> Type :=
| push : forall n : nat, nat -> Prog n -> Prog (S n)
| pop : forall n : nat, Prog (S n) -> Prog n.
Fixpoint eval (n : nat) (p : Prog n) : t nat n :=
match p with
| push _ n p => cons _ n _ (eval _ p)
| pop _ p => match eval _ p with
| cons _ _ _ stack => stack
end
end.
Теперь я хочу добавить инструкцию pop'
, которая извлекает элемент из стека, но может применяться только тогда, когда в стеке есть хотя бы два элемента.
Inductive Prog : nat -> Type :=
| push : forall n : nat, nat -> Prog n -> Prog (S n)
| pop' : forall n : nat, Prog (S (S n)) -> Prog (S n).
При использовании того же Fixpoint
, как указано выше (изменение pop
на pop'
), я получаю ошибку
Термин "стек" имеет тип "t nat n0", в то время как ожидается, что он будет иметь тип "t nat (S k)".
Так что я думал, что смогу сделать это с Program
. Поэтому я использую:
Require Import Coq.Program.Tactics Coq.Logic.JMeq.
Program Fixpoint eval (n : nat) (p : Prog n) : t nat n :=
match p with
| push _ n p => cons _ n _ (eval _ p)
| pop' k p => match eval _ p with
| cons _ l _ stack => stack
| nil _ => _
end
end.
Однако по какой-то причине это порождает странные обязательства, которые, я не думаю, могут быть решены. Первое (из двух) обязательство, оставшееся после автоматических попыток:
k : nat
p0 : Prog (S k)
p : Prog (S (S k))
Heq_p : JMeq (pop' k p) p0
l, n0 : nat
stack : t nat n0
h : nat
t : t nat n0
Heq_anonymous0 : JMeq (cons nat l n0 stack) (cons nat h n0 t)
______________________________________(1/1)
n0 = S k
Я не вижу способа связать k
, который является аргументом типа для Prog
, и n0
, который является аргументом типа для векторного типа t
.
Почему это Program
приводит к этой странной обязанности, и как я могу написать функцию оценки, обходящую эту проблему?