如何在伊莎贝尔的ML级别轻松编写简单的策略?

时间:2013-03-05 06:12:26

标签: sml isabelle

在Isabelle理论文件中,我可以编写简单的单行策略,如下所示:

apply (clarsimp simp: split_def split: prod.splits)
然而,我发现,当我开始编写ML代码来自动化证明,生成ML tactic对象时,这些单行变得相当冗长:

clarsimp_tac (Context.proof_map (
    Simplifier.map_ss (fold Splitter.add_split @{thms prod.splits})
    #> Simplifier.map_ss (fn ss => ss addsimps [@{thm split_def}]))
  @{context}) 1

是否有更简单的方法来编写Isabelle / ML级别的简单单线战术?

例如,类似反引语:@{tactic "clarsimp simp: split_def split: prod.splits"}生成context -> tactic类型的函数,将是一种理想的解决方案。

3 个答案:

答案 0 :(得分:5)

我看到了各种各样的可能性,它取决于你的应用程序的上下文什么是最好的。请注意,一般情况下,自动校对的单个ML代码曾经在过去很常见,但今天相对较少。例如,将相当小的HOL-Bali(1997年开始)中的自定义策略数量与法新社中的大JinjaThreads进行比较(从2007年开始,一直持续到最近)。

@{tactic}那样嵌套ML反引号原则上是可行的,但是你会很快遇到更多的问题,比如你的定理论点应该再次是Isar或ML源会发生什么。

而不是ML中的反引用战术构建块,更基本的方法是通过给出常规方法语法来引用你在Isar中的证明程序:

ML {*
  (*foo_tac -- the payload of what you want to do,
    note the dependency on ctxt: Proof.context*)
  fun foo_tac ctxt =
    let
      val my_ctxt =
        ctxt |> Simplifier.map_simpset
         (fold Splitter.add_split @{thms prod.splits} #>
          Simplifier.add_simp @{thm split_def})
    in ALLGOALS (clarsimp_tac my_ctxt) end
*}

method_setup foo = {*
  (*concrete syntax like "clarsimp", "auto" etc.*)
  Method.sections Clasimp.clasimp_modifiers >>
    (*Isar method boilerplate*)
    (fn _ => fn ctxt => SIMPLE_METHOD (CHANGED (foo_tac ctxt)))  
*}

这里我首先在Isabelle / ML中制定了一个传统的foo_tac定义,然后用通常的Isar方式将其作为证明方法。后者意味着你有像SIMPLE_METHOD这样的包装器负责将“链式事实”推入你的目标状态,而CHANGED则确保Isar方法取得进展(如simp或{{1} }})。

auto示例假定您通过硬连线拆分规则修改上下文(或其simpset)是不变的。如果您想在那里有更多参数,可以在具体方法语法中包含它。请注意,foo_tac在这方面已经相当复杂。更多基本的参数解析器在isar-ref手册的“定义证明方法”一节中给出。您还应该通过搜索Method.sections(在Isabelle / Isar中)或method_setup(在Isabelle / ML中)的来源来查看现有示例。

如果您仍然想要使用ML反引号而不是具体的方法语法,可以尝试使用Method.setup的变体来允许这样的修饰符:

@{context}

这有点推测,在现场发明,可能会成为不好的做法。正如我所说,尽管ML是Isabelle框架中不可或缺的一部分,但近年来Isabelle的细粒度战术编程变得有点用完了。如果您提出更具体的问题与更多的应用程序上下文,我们可以重新考虑反引用方法。

答案 1 :(得分:3)

除了其他答案之外,我认为值得一提的是,Isabelle2015中有一种新的高级战术/证明方法构造语言(类似于Coq中的Ltac),名为Eisbach,旨在更容易理解和维护。

答案 2 :(得分:1)

Method类似乎提供了足够的界面来通过cases_tactic提取策略,如下所示:

(*
 * Generate an ML tactic object of the given Isar string.
 *
 * For example,
 *
 *   mk_tac "auto simp: field_simps intro!: ext" @{context}
 *
 * will generate the corresponding "tactic" object.
 *)
fun mk_tac str ctxt =
let
  val parsed_str = Outer_Syntax.scan Position.start str
      |> filter Token.is_proper
      |> Args.name
  val meth = Method.method (Proof_Context.theory_of ctxt)
      (Args.src (parsed_str, Position.start)) ctxt
in
  Method.apply (K meth) ctxt [] #> Seq.map snd
end

或者作为反引用:

(*
 * Setup an antiquotation of the form:
 *
 *    @{tactic "auto simp: foo intro!: bar"}
 *
 * which returns an object of type "context -> tactic".
 *
 * While this doesn't provide any benefits over a direct call to "mk_tac" just
 * yet, in the future it may generate code to avoid parsing the tactic at
 * run-time.
 *)
val tactic_antiquotation_setup =
let
  val parse_string =
    ((Args.context -- Scan.lift Args.name) >> snd)
      #>> ML_Syntax.print_string
      #>> (fn s => "mk_tac " ^ s)
      #>> ML_Syntax.atomic
in
  ML_Antiquote.inline @{binding "tactic"} parse_string
end

并在理论文件中设置如下:

setup {*
  tactic_antiquotation_setup
*}

然后可以按如下方式使用:

lemma "(a :: nat) * (b + 1) = (a * b) + a"
  by (tactic {* @{tactic "metis Suc_eq_plus1 mult_Suc_right nat_add_commute"} @{context} *})

根据需要。