Я хотел бы определить следующую функцию, используя Program Fixpoint
или Function
в Coq:
Require Import Coq.Lists.List.
Import ListNotations.
Require Import Coq.Program.Wf.
Require Import Recdef.
Inductive Tree := Node : nat -> list Tree -> Tree.
Fixpoint height (t : Tree) : nat :=
match t with
| Node x ts => S (fold_right Nat.max 0 (map height ts))
end.
Program Fixpoint mapTree (f : nat -> nat) (t : Tree) {measure (height t)} : Tree :=
match t with
Node x ts => Node (f x) (map (fun t => mapTree f t) ts)
end.
Next Obligation.
К сожалению, на данный момент у меня есть обязательство по доказыванию height t < height (Node x ts)
, не зная, что t
является членом ts
.
Аналогично с Function
вместо Program Fixpoint
, только Function
обнаруживает проблему и прерывает определение:
Error: the term fun t : Tree => mapTree f t can not contain a recursive call to mapTree
Я ожидаю получить обязательство по доказательству In t ts → height t < height (Node x ts)
.
Есть ли способ добиться этого, не требующий реструктуризации определения функции? (Я знаю обходные пути, которые требуют, например, встраивания здесь определения map
- я бы хотел избежать этого.)
Изабель
Чтобы оправдать это ожидание, позвольте мне показать, что происходит, когда я делаю то же самое в Isabelle, используя команду function
, которая (AFAIK) связана с командой Coq Function
:
theory Tree imports Main begin
datatype Tree = Node nat "Tree list"
fun height where
"height (Node _ ts) = Suc (foldr max (map height ts) 0)"
function mapTree where
"mapTree f (Node x ts) = Node (f x) (map (λ t. mapTree f t) ts)"
by pat_completeness auto
termination
proof (relation "measure (λ(f,t). height t)")
show "wf (measure (λ(f, t). height t))" by auto
next
fix f :: "nat ⇒ nat" and x :: nat and ts :: "Tree list" and t
assume "t ∈ set ts"
thus "((f, t), (f, Node x ts)) ∈ measure (λ(f, t). height t)"
by (induction ts) auto
qed
В доказательстве прекращения я получаю предположение t ∈ set ts
.
Обратите внимание, что Изабель не требует подтверждения об отключении вручную, и следующее определение работает нормально:
fun mapTree where
"mapTree f (Node x ts) = Node (f x) (map (λ t. mapTree f t) ts)"
Это работает, потому что функция map
имеет «лемму сравнения» вида
xs = ys ⟹ (⋀x. x ∈ set ys ⟹ f x = g x) ⟹ map f xs = map g ys
что команда function
использует, чтобы узнать, что доказательство прекращения должно учитывать только t ∈ set ts
..
Если такой леммы нет, например потому что я определяю
definition "map' = map"
и использую это в mapTree
, я получаю такое же недоказуемое обязательство доказательства, что и в Coq. Я могу заставить его снова работать, объявив лемму о сопоставлении для map'
, например с использованием
declare map_cong[folded map'_def,fundef_cong]