0

I have the following language of records:

datatype "term" = Rcd "string ⇀ term"

fun id_term :: "term ⇒ term" 
  where "id_term (Rcd vals) = Rcd (map_option id_term ∘ vals)"

This doesn't pass the termination checker, because the type's size function is constantly 0. I don't see how to provide a computable measure either without constraining the map to a finite domain.

So: How can I prove termination for the above definition? I suspect I have to prove well-foundedness for some inductive predicate over terms, but I'm not really sure how to do that.

Sebastian Graf
  • 3,602
  • 3
  • 27
  • 38

2 Answers2

2

You can define this function using primrec:

primrec id_term :: "term ⇒ term"
  where "id_term (Rcd vals) = Rcd (map_option id_term ∘ vals)"

primrec allows you to use the map functions of the involved type constructors. In your case, that's map_option and op ∘.

larsrh
  • 2,579
  • 8
  • 30
2

For non-primitively-recursive functions, you can also use the function command, but things get a bit more complicated due to the fact that you don't have a size measure. Essentially, you have to define a subterm relation and show that it is well-founded, and then you can use that to show that your function terminates:

datatype "term" = Rcd "string ⇀ term"

inductive subterm :: "term ⇒ term ⇒ bool" where
  "t ∈ ran f ⟹ subterm t (Rcd f)"

lemma accp_subterm: "Wellfounded.accp subterm t"
proof (induction t)
  case (Rcd f)
  have IH: "Wellfounded.accp subterm t" if "t ∈ ran f" for t
    using Rcd[of "Some t" t] and that by (auto simp: eq_commute ran_def)
  show ?case by (rule accpI) (auto intro: IH elim!: subterm.cases)
qed

definition subterm_rel where "subterm_rel = {(t, Rcd f) |f t. t ∈ ran f}"

lemma subterm_rel_altdef: "subterm_rel = {(s, t) |s t. subterm s t}"
  by (auto simp: subterm_rel_def subterm.simps)

lemma subterm_relI [intro]: "t ∈ ran f ⟹ (t, Rcd f) ∈ subterm_rel"
  by (simp add: subterm_rel_def)

lemma subterm_relI' [intro]: "Some t = f x ⟹ (t, Rcd f) ∈ subterm_rel"
  by (auto simp: subterm_rel_def ran_def)

lemma wf_subterm_rel [simp, intro]: "wf subterm_rel"
  using accp_subterm unfolding subterm_rel_altdef accp_eq_acc wf_acc_iff by simp

function id_term :: "term ⇒ term" 
  where "id_term (Rcd vals) = Rcd (map_option id_term ∘ vals)"
by pat_completeness simp_all
termination by (relation subterm_rel) auto
Manuel Eberl
  • 7,858
  • 15
  • 24
  • Wow, that's quite a mouthful, as I suspected. Thanks for your efforts! Although the simple `primrec` solution was enough for my purposes, this probably qualifies more as an answer to the question I asked. – Sebastian Graf Apr 24 '17 at 11:52
  • Note that I'm not sure this is the *easiest* way to define that relation; it was just the first thing I tried and it worked reasonably well. I kind of would have expected the datatype package to generate something like this by default, but apparently not. You can also use the transitive closure of `subterm_rel` as your relation, which gives you a bit more flexibility. – Manuel Eberl Apr 24 '17 at 15:21
  • Not really related to the question at hand, but is there some library solution for reflexive and transitive closures of binary relations? – Sebastian Graf Apr 24 '17 at 20:33
  • 1
    Have a look at `~~/src/HOL/Transitive_Closure.thy`. It has `reflcl`, `trancl`, and `rtrancl` for the reflexive/transitive/reflexive-transitive closure of a binary relation (modelled as a set of pairs). There are also variants with a `p` at the end for binary relations modelled as binary predicates. – Manuel Eberl Apr 25 '17 at 06:02