Sml 我如何在Isabelle的ML级别轻松编写简单的战术?

Sml 我如何在Isabelle的ML级别轻松编写简单的战术?,sml,isabelle,Sml,Isabelle,在Isabelle理论文件中,我可以编写简单的单行策略,如以下内容: apply (clarsimp simp: split_def split: prod.splits) 然而,我发现,当我开始编写ML代码来自动校对,生成ML策略对象时,这些一行代码变得相当冗长: clarsimp_tac (Context.proof_map ( Simplifier.map_ss (fold Splitter.add_split @{thms prod.splits}) #> Sim

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

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

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级别,有没有更简单的方法来编写简单的单行策略


例如,像反引号:
@{tractic“clarsimp-simp:split_def split:prod.splits”}
生成类型为
context->tractic
的函数将是一个理想的解决方案。

我看到了各种可能性,这取决于应用程序的上下文。请注意,一般来说,在非常古老的时代,用于自动校对的单个ML代码曾经是常见的地方,但今天它相对较少。例如,比较小规模(始于1997年)和大规模(始于2007年,一直持续到最近)的定制战术数量

嵌套ML反旋转,如
@{tractic}
原则上是可行的,但您会很快遇到进一步的问题,例如如果您的定理参数再次是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)))  
*}
@{context simp add: ...}
在这里,我首先在Isabelle/ML中定义了一个传统的
foo\u tac
定义,然后用通常的Isar方法将其包装起来作为证明方法。后者意味着您拥有像
SIMPLE\u METHOD
这样的包装器,负责将“链接事实”推到您的目标状态,并且
更改了
,以确保Isar方法取得进展(比如
simp
auto

foo_tac
示例假定您对上下文(或其simpset)的修改根据硬连线分割规则是恒定的。如果您想在那里有更多的参数,可以将其包含在具体的方法语法中。请注意,
Method.sections
在这方面已经相当成熟了。手册的“定义证明方法”一节中给出了更基本的参数解析器。您还应该通过搜索
method\u setup
(在Isabelle/Isar中)或
method.setup
(在Isabelle/ML中)的源代码来查看现有示例

如果您仍然希望执行ML AntiVotations而不是具体的方法语法,可以尝试使用
@{context}
的一种变体,该变体允许使用如下修饰符:

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)))  
*}
@{context simp add: ...}

这有点投机,是当场发明的,结果可能是一种不好的做法。正如我所说的,虽然ML是Isabelle框架的一个组成部分,但近年来Isabelle中的细粒度策略编程有点过时了。如果您对更多的应用程序上下文提出更具体的问题,我们可以重新考虑反旋转方法。

方法
类似乎提供了足够的接口,通过
案例策略
提取策略,如下所示:

(*
 * 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 {*
  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} *})
或者作为反报价:

(*
 * 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
并在理论文件中设置,如下所示:

(*
 * 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 {*
  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} *})
然后可按如下方式使用:

(*
 * 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 {*
  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} *})

根据需要。

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

我并不热衷于使用反报价(如何从ML变量中添加参数是一个很好的观点),但我只是在寻找一种方便的方法来实例化现成的Isabelle策略(例如
clarsimp
auto
,等等)从ML代码内部。上下文是项目,它需要根据用户C代码自动生成许多证明。使用我在问题中使用的Isabelle ML接口编写/原型化此类自动证明方法可能会变得非常乏味。上面的
foo_tac
method
示例就是这样的意思clarsimp的一个“方便的实例化”,auto。您没有内联大型
策略
ML表达式,而是混合了辅助ML策略和Isar方法语法。您还可以以Isabelle源代码中的src/HOL/Auth为例,了解许多特定的ML策略和Isar方法(这是1990年ies中伊莎贝尔的经典战术应用程序的更新版本).
src/HOL/Auth
似乎在手工编写理论文件中精心设计方法来帮助解决定理。在我的上下文中,我正在解决基于输入C文件动态创建的定理——底部没有证明脚本,而是处理由
Goal.init
生成的
thm
对象,而h需要一个
策略来处理。在开发这种策略时,我通常只想使用“内置”Isabelle战术,但没有为每一次这样的使用生成一个相当于
foo_tac
正文的冗长。你可能想研究
try0
的代码。好吧,它做了一个与你提出的反引号类似的把戏。@LarsNoschinski:
try0
最初看起来很有希望,但不幸的是,它在使用中起了作用ng证明状态(
状态
)对象,在需要
策略的情况下仍然无法使用。一种可能的方法是将部分验证的
thm
注入新的证明状态对象,对其应用方法,然后提取结果;不幸的是,似乎也没有明显的机制来执行此操作。有几个问题答案和评论散布在他们身上,这让人有点难以理解。最好在
isabelle users
开始一个简单的旧邮件列表讨论。