为排序算法生成代码的最简单方法是什么,该算法以相反的顺序对其参数进行排序,同时构建在现有List.sort
之上?
我提出了两个解决方案,如下所示。但他们两个都不是很满意。
还有其他想法可以做到这一点吗?
答案 0 :(得分:0)
我提出了两种可能的解决方案。但两者都有(严重)缺点。 (我本想几乎自动获得结果。)
介绍一种Haskell风格的新类型。例如,如果我们想要对nat
的列表进行排序,例如
datatype 'a new = New (old : 'a)
instantiation new :: (linorder) linorder
begin
definition "less_eq_new x y ⟷ old x ≥ old y"
definition "less_new x y ⟷ old x > old y"
instance by (default, case_tac [!] x) (auto simp: less_eq_new_def less_new_def)
end
此时
value [code] "sort_key New [0::nat, 1, 0, 0, 1, 2]"
产生所需的反向排序。虽然这相对容易,但它不像我想要的解决方案那样自动,而且还有一个小的运行时开销(因为Isabelle没有Haskell的 newtype
)。 / p>
通过区域设置获得线性顺序的对偶。首先,我们或多或少地复制现有代码以进行插入排序(但不是依赖于类型类,而是使用表示比较的参数显式)。
fun insort_by_key :: "('b ⇒ 'b ⇒ bool) ⇒ ('a ⇒ 'b) ⇒ 'a ⇒ 'a list ⇒ 'a list"
where
"insort_by_key P f x [] = [x]"
| "insort_by_key P f x (y # ys) =
(if P (f x) (f y) then x # y # ys else y # insort_by_key P f x ys)"
definition "revsort_key f xs = foldr (insort_by_key (op ≥) f) xs []"
此时我们有revsort_key
的代码。
value [code] "revsort_key id [0::nat, 1, 0, 0, 1, 2]"
但我们也希望在linorder
语言环境(来自linorder
类)中已经证明的所有好结果。为此,我们引入线性顺序的双重性并使用“mixin”(不确定我是否在这里使用正确的命名)来替换所有出现的linorder.sort_key
(不允许代码生成)通过我们新的“代码常量”revsort_key
。
interpretation dual_linorder!: linorder "op ≥ :: 'a::linorder ⇒ 'a ⇒ bool" "op >"
where
"linorder.sort_key (op ≥ :: 'a ⇒ 'a ⇒ bool) f xs = revsort_key f xs"
proof -
show "class.linorder (op ≥ :: 'a ⇒ 'a ⇒ bool) (op >)" by (rule dual_linorder)
then interpret rev_order: linorder "op ≥ :: 'a ⇒ 'a ⇒ bool" "op >" .
have "rev_order.insort_key f = insort_by_key (op ≥) f"
by (intro ext) (induct_tac xa; simp)
then show "rev_order.sort_key f xs = revsort_key f xs"
by (simp add: rev_order.sort_key_def revsort_key_def)
qed
虽然使用这个解决方案我们没有任何运行时损失,但它对我的口味来说太过冗长并且不容易适应标准代码设置的变化(例如,如果我们想要使用我们所有排序操作的Archive of Formal Proofs的mergesort实现。)