Isabelle 关注Eisbach中的新子目标

Isabelle 关注Eisbach中的新子目标,isabelle,Isabelle,在艾斯巴赫,我可以使用将方法应用于由方法创建的所有新子目标。 但是,我经常知道创建了多少子目标,并且希望对新的子目标应用不同的方法。 有没有一种说法像“将方法X应用于第一个新的子目标,将方法Y应用于第二个新的子目标” 下面是一个简单的用例: 我想开发一种方法,可以处理任意长度但结构相同的两个连接。 该方法应可用于显示连词1暗示连词2,通过显示该暗示对每个组件有效。 它应该是这样使用的: lemma example: assumes c: "a 0 ∧ a 1 ∧ a 2 ∧ a 3"

在艾斯巴赫,我可以使用
将方法应用于由方法创建的所有新子目标。 但是,我经常知道创建了多少子目标,并且希望对新的子目标应用不同的方法。 有没有一种说法像“将方法X应用于第一个新的子目标,将方法Y应用于第二个新的子目标”

下面是一个简单的用例:

我想开发一种方法,可以处理任意长度但结构相同的两个连接。 该方法应可用于显示连词1暗示连词2,通过显示该暗示对每个组件有效。 它应该是这样使用的:

lemma example:
  assumes c: "a 0 ∧ a 1 ∧ a 2  ∧ a 3"
    and imp: "⋀i. a i ⟹ a' i"
  shows "a' 0 ∧ a' 1 ∧ a' 2 ∧ a' 3"
proof (conj_one_by_one pre: c)
  show "a 0 ⟹ a' 0" by (rule imp)
  show "a 1 ⟹ a' 1" by (rule imp)
  show "a 2 ⟹ a' 2" by (rule imp)
  show "a 3 ⟹ a' 3" by (rule imp)
qed
在Eisbach中实现此方法时,在使用
rule conjI
后,我遇到了一个问题。 我有两个子目标,我想递归地处理,但我想对这两种情况使用不同的事实

我提出了以下解决方法,它使用人工标记两个子目标,有点难看:

definition "marker_L x ≡ x"
definition "marker_R x ≡ x"

lemma conjI_marked: 
  assumes "marker_L P" and "marker_R Q"
  shows "P ∧ Q"
  using assms unfolding marker_L_def marker_R_def by simp


method conj_one_by_one uses pre = (
    match pre in 
      p: "?P ∧ ?Q" ⇒ ‹
        (unfold marker_L_def marker_R_def)?, 
        rule conjI_marked;( 
            (match conclusion in "marker_L _" ⇒ ‹(conj_one_by_one pre: p[THEN conjunct1])?›)
          | (match conclusion in "marker_R _" ⇒ ‹(conj_one_by_one pre: p[THEN conjunct2])?›))›)
    | ((unfold marker_L_def marker_R_def)?, insert pre)

这不是一个完整的答案,但您可能能够从这里所述的内容中获得一些有用的信息

在艾斯巴赫我可以使用;将方法应用于创建的所有新子目标 用一种方法。然而,我经常知道创建了多少子目标,并且 希望对新的子目标应用不同的方法。有没有 类似于“将方法X应用于第一个新的子目标并 方法Y到第二个新子目标“

您可以使用标准战术
范围
来定义您自己的战术,您可以将其应用于连续的子目标。我在下面提供了一个非常专门且大大简化的用例:

ML‹

fun mytac ctxt thms = thms
  |> map (fn thm => resolve_tac ctxt (single thm))
  |> RANGE

›

lemma 
  assumes A: A and B: B and C: C
  shows "A ∧ B ∧ C"
  apply(intro conjI)
  apply(tactic‹mytac @{context} [@{thm A}, @{thm B}, @{thm C}] 1›)
  done
希望,将其扩展到更复杂的用例应该相当容易(同时比我更小心子目标索引:您可能还需要
SELECT\u-GOAL
,以确保实现是安全的)。虽然在上面的例子中,mytac接受了一系列定理,但应该很容易看出这些定理是如何被战术所取代的,并且通过进一步的工作,战术可以包装成一种高阶方法


我想开发一种方法,可以处理任意两个连接 长度相同,但结构相同。该方法应可用于 通过以下方式显示连词1暗示连词2 对每个组件都适用。它应该是这样使用的:

lemma example:
  assumes c: "a 0 ∧ a 1 ∧ a 2  ∧ a 3"
    and imp: "⋀i. a i ⟹ a' i"
  shows "a' 0 ∧ a' 1 ∧ a' 2 ∧ a' 3"
proof (conj_one_by_one pre: c)
  show "a 0 ⟹ a' 0" by (rule imp)
  show "a 1 ⟹ a' 1" by (rule imp)
  show "a 2 ⟹ a' 2" by (rule imp)
  show "a 3 ⟹ a' 3" by (rule imp)
qed
更新

再看一下这个问题,似乎有一个更自然的解决方案。解决方案遵循原始答案的大纲,但元蕴涵被HOL的对象逻辑蕴涵所取代(可以使用
原子化(完整)
导入impI
实现“往返”转换):


遗留问题(这是原始答案的一部分,但由于上面建议的更新,几乎不相关)

如果这是您考虑的唯一应用程序,可能有一个基于以下迭代过程的合理自然的解决方案:

lemma arg_imp2: "(a ⟹ b) ⟹ (c ⟹ d) ⟹ ((a ∧ c) ⟹ (b ∧ d))" by auto

lemma example:
  assumes c: "a 0 ∧ a 1 ∧ a 2 ∧ a 3"
    and imp: "⋀i. a i ⟹ a' i"
  shows "a' 0 ∧ a' 1 ∧ a' 2 ∧ a' 3"
  using c
  apply(intro arg_imp2[of ‹a 0› ‹a' 0› ‹a 1 ∧ a 2 ∧ a 3› ‹a' 1 ∧ a' 2 ∧ a' 3›])
  apply(rule imp)
  apply(assumption)
  apply(intro arg_imp2[of ‹a 1› ‹a' 1› ‹a 2 ∧ a 3› ‹a' 2 ∧ a' 3›])
  apply(rule imp)
  apply(assumption)
  apply(intro arg_imp2[of ‹a 2› ‹a' 2› ‹a 3› ‹a' 3›])
  apply(rule imp)
  apply(assumption)
  apply(rule imp)
  apply(assumption+)
  done

我不确定在Eisbach中表达这一点有多容易,但在
Isabelle/ML

中表达这一点应该是相当容易的。使用用户9716869的指针,我能够编写一个实现我想要的方法:

ML‹

fun split_with_tac (tac1:  int -> tactic) (ts: (int -> tactic) list) (i: int) (st: thm): thm Seq.seq =
    let 
      val st's = tac1 i st
      fun next st' = 
        let 
          val new_subgoals_count = 1 + Thm.nprems_of st' - Thm.nprems_of st 
        in
          if new_subgoals_count <> length ts then Seq.empty
          else
            RANGE ts i st'
        end
    in
      st's |> Seq.maps next
    end


fun tok_to_method_text ctxt tok =
    case Token.get_value tok of
      SOME (Token.Source src) => Method.read ctxt src
    | _ =>
        let
          val (text, src) = Method.read_closure_input ctxt (Token.input_of tok);
          val _ = Token.assign (SOME (Token.Source src)) tok;
        in text end 

val readText: Token.T Token.context_parser = Scan.lift (Parse.token Parse.text)

val text_and_texts_closure: (Method.text * Method.text list) Token.context_parser =
  (Args.context -- readText -- (Scan.lift \<^keyword>‹and› |-- Scan.repeat readText)) >> (fn ((ctxt, tok), t) =>
    (tok_to_method_text ctxt tok, map (tok_to_method_text ctxt) t));

›

method_setup split_with = 
‹text_and_texts_closure >> (fn (m, ms) => fn ctxt => fn facts =>
   let
     fun tac m st' =
       method_evaluate m ctxt facts
     fun tac' m i st' =
       Goal.restrict i 1 st'
       |> method_evaluate m ctxt facts
       |> Seq.map (Goal.unrestrict i)
      handle THM _ => Seq.empty
     val initialT: int -> tactic = tac' m
     val nextTs: (int -> tactic) list = map tac' ms
   in SIMPLE_METHOD (HEADGOAL (split_with_tac initialT nextTs)) facts end)
›



lemma 
  assumes r: "P ⟹ Q ⟹ R"
    and p: "P" 
    and q: "Q"
  shows "R"
  by (split_with ‹rule r› and ‹rule p›  ‹rule q›)

method conj_one_by_one uses pre = (
    match pre in 
      p: "?P ∧ ?Q" ⇒ ‹split_with ‹rule conjI› and 
                            ‹conj_one_by_one pre: p[THEN conjunct1]›
                            ‹conj_one_by_one pre: p[THEN conjunct2]››
      | insert pre)

lemma example:
  assumes c: "a 0 ∧ a 1 ∧ a 2  ∧ a 3"
    and imp: "⋀i. a i ⟹ a' i"
  shows "a' 0 ∧ a' 1 ∧ a' 2 ∧ a' 3"
proof (conj_one_by_one pre: c)
  show "a 0 ⟹ a' 0" by (rule imp)
  show "a 1 ⟹ a' 1" by (rule imp)
  show "a 2 ⟹ a' 2" by (rule imp)
  show "a 3 ⟹ a' 3" by (rule imp)
qed
MLè
有趣的拆分(tac1:int->战术)(ts:(int->战术)列表)(i:int)(st:thm):thm Seq.Seq=
让
瓦尔街=塔西街1号
有趣的下一站
让
val new_SUBSGOLES_count=1+Thm.nprems_of st'-Thm.nprems_of st
在里面
如果新的子目标计数长度ts,则Seq.empty
其他的
射程
结束
在里面
st's |>下一步的顺序地图
结束
fun tok_to_method_text ctxt tok=
case Token.get_值tok of
SOME(Token.Source src)=>Method.read ctxt src
| _ =>
让
val(text,src)=Method.read_closure_input ctxt(tok的Token.input_);
val=Token.assign(SOME(Token.Source src))tok;
文末
val readText:Token.T Token.context_parser=Scan.lift(Parse.Token Parse.text)
val text_和_text_闭包:(Method.text*Method.text list)Token.context_解析器=
(Args.context--readText--(Scan.lift\è和›|--Scan.repeat readText))>>(fn((ctxt,tok),t)=>
(tok_to_方法_text ctxt tok,map(tok_to_方法_text ctxt)t));
›
方法\u设置拆分\u与=
ètext_和_text_closure>>(fn(m,ms)=>fn ctxt=>fn facts=>
让
趣味塔克m街=
方法\u评估m ctxt事实
有趣的tac'm我是=
目标。限制我1'
|>方法\u评估m ctxt事实
|>序列图(目标一)
句柄THM=>Seq.empty
val缩写:int->tractic=tac'm
val nextTs:(内部->战术)列表=地图战术'ms
在简单方法中(HEADGOAL(使用首字母nextTs拆分)事实结束)
›
引理
假设r:P⟹ Q⟹ R“
和p:“p”
和q:“q”
显示“R”
由(使用è规则r›和è规则p›è规则q›拆分)
方法conj_one_by_one使用pre=(
预赛
p:“?p∧ ?Q“⇒ ‹用è规则连体›和
èconj_one_by_one pre:p[然后conconconnct1]›
èconj_one_one_one pre:p[然后conconconnct2]›
|插入预编码)
引理示例:
假设c:“一个0∧ a 1∧ a 2∧ a 3“
和小鬼:“⋀i、 a我⟹ “我”
显示“a'0”∧ a'1∧ a'2∧ a‘3’
证明(c)
显示“0”⟹ “0”由(规则导入)
显示“a 1”⟹ a“1”由(规则imp)
显示“a 2”⟹ a“2”由(规则imp)
显示“a 3”⟹ a“3”由(规则imp)
量化宽松

谢谢,我可以使用
范围
做我想做的事情,请参见下面的答案。根据我的答案中的迭代过程,似乎存在一个更自然的解决方案:请参见更新。