使用Isabelle的代码生成器:数据细化和更高阶函数

时间:2013-04-29 07:59:44

标签: code-generation isabelle

这是Isabelle's Code generation: Abstraction lemmas for containers?的后续行动:

我想在以下理论中为the_question生成代码:

theory Scratch imports Main begin

typedef small = "{x::nat. x < 10}" morphisms to_nat small
  by (rule exI[where x = 0], simp)
code_datatype small
lemma [code abstype]: "small (to_nat x) = x" by (rule to_nat_inverse)

definition a_pred :: "small ⇒ bool"
  where "a_pred = undefined"

definition "smaller j = [small i . i <- [0 ..< to_nat j]]" 

definition "the_question j = (∀i ∈ set (smaller j). a_pred j)"

问题在于smaller的等式不适合代码生成,因为它提到了抽象函数small

现在根据Andreas对我的上一个问题和关于数据优化的论文的回答,下一步是为小数字集引入一个类型,并为该类型中的smaller创建一个定义:

typedef small_list = "{l. ∀x∈ set l. (x::nat) < 10}" by (rule exI[where x = "[]"], auto)
code_datatype Abs_small_list
lemma [code abstype]: "Abs_small_list (Rep_small_list x) = x" by (rule Rep_small_list_inverse)

definition "smaller' j = Abs_small_list [ i . i <- [0 ..< to_nat j]]"
lemma smaller'_code[code abstract]: "Rep_small_list (smaller' j) = [ i . i <- [0 ..< to_nat j]]"
  unfolding smaller'_def
  by (rule Abs_small_list_inverse, cases j, auto elim: less_trans simp add: small_inverse)

现在smaller'是可执行的。根据我的理解,我需要重新定义small list上的操作作为small_list上的操作:

definition "small_list_all P l = list_all P (map small (Rep_small_list l))"

lemma[code]: "the_question j = small_list_all a_pred (smaller' j)"
  unfolding small_list_all_def the_question_def smaller'_code smaller_def Ball_set by simp

我可以为the_question定义好看的代码方程式。但是small_list_all的定义不适合代码生成,因为它提到了抽象态射small。如何使small_list_all可执行文件?

(注意我无法解开a_pred的代码方程,因为问题实际上出现在实际递归a_pred的代码方程中。另外,我想避免涉及re的hack - 在运行时检查不变量。)

2 个答案:

答案 0 :(得分:2)

我对一般问题没有很好的解决方案,但是这个想法会让你在这种特殊情况下为the_question生成代码。

首先,使用抽象代码方程式定义函数predecessor :: "small ⇒ small(可能使用lift_definition中的λn::nat. n - 1

现在你可以为smaller证明一个新的代码等式,其rhs使用if-then-else,predecessor和普通列表操作:

lemma smaller_code [code]:
  "smaller j = (if to_nat j = 0 then []
    else let k = predecessor j in smaller k @ [k])"

(如果您愿意定义辅助功能,当然可以实现更有效的实现。)

代码生成现在应该适用于smaller,因为此代码方程式不使用函数small

答案 1 :(得分:0)

简短回答是no, it does not work

答案很长,经常有变通方法。布莱恩在答案中展示了一个。一般的想法似乎是

  

将除了最终返回值之外的协变位置中具有抽象类型的函数(即返回抽象值的容器的高阶函数或函数)分离为多个辅助函数,以便抽象值仅构造为单个返回值1帮助函数。

在Brian的例子中,这个函数是predecessor。或者,作为另一个简单的例子,假设一个函数

definition smallPrime :: "nat ⇒ small option"
  where "smallPrime n = (if n ∈ {2,3,5,7} then Some (small n) else None)"

由于small的出现,此定义不是有效的代码方程式。但这得出一个:

definition smallPrimeHelper :: "nat ⇒ small"
  where "smallPrimeHelper n = (if n ∈ {2,3,5,7} then small n else small 0)"
lemma [code abstract]: "to_nat (smallPrimeHelper n) = (if n ∈ {2,3,5,7} then n else 0)"
  by (auto simp add: smallPrimeHelper_def intro: small_inverse)
lemma [code_unfold]: "smallPrime n = (if n ∈ {2,3,5,7} then Some (smallPrimeHelper n) else None)"
  unfolding smallPrime_def smallPrimeHelper_def by simp

如果想要避免谓词的冗余计算(可能比∈ {2,3,5,7}更复杂),可以通过引入抽象视图使得帮助器的返回类型更智能,即包含两者的类型计算的结果,以及从中构造抽象类型所需的信息:

typedef smallPrime_view = "{(x::nat, b::bool). x < 10 ∧ b = (x ∈ {2,3,5,7})}"
  by (rule exI[where x = "(2, True)"], auto)
setup_lifting type_definition_small
setup_lifting type_definition_smallPrime_view

对于视图,我们有一个构建它的函数和访问器,它们将结果分开,有一些关于它们的引理:

lift_definition smallPrimeHelper' :: "nat ⇒ smallPrime_view"
  is "λ n. if n ∈ {2,3,5,7} then (n, True) else (0, False)" by simp
lift_definition smallPrimeView_pred :: "smallPrime_view ⇒ bool"
  is "λ spv :: (nat × bool) . snd spv" by auto
lift_definition smallPrimeView_small :: "smallPrime_view ⇒ small"
  is "λ spv :: (nat × bool) . fst spv" by auto
lemma [simp]: "smallPrimeView_pred (smallPrimeHelper' n) ⟷ (n ∈ {2,3,5,7})"
  by transfer simp
lemma [simp]: "n ∈ {2,3,5,7} ⟹ to_nat (smallPrimeView_small (smallPrimeHelper' n)) = n"
  by transfer auto
lemma [simp]: "n ∈ {2,3,5,7} ⟹ smallPrimeView_small (smallPrimeHelper' n) = small n"
  by (auto intro: iffD1[OF to_nat_inject] simp add: small_inverse)

有了这个,我们可以得到一个只进行一次检查的代码方程式:

lemma [code]: "smallPrime n = 
  (let spv = smallPrimeHelper' n in
   (if smallPrimeView_pred spv
    then Some (smallPrimeView_small spv)
    else None))"
   by (auto simp add: smallPrime_def Let_def)