如何定义具有约束的数据类型?

时间:2017-09-01 07:56:54

标签: isabelle

例如,我需要为列表对定义数据类型,这两个列表必须具有相同的长度:

type_synonym list2 = "nat list × nat list"

definition good_list :: "list2" where
  "good_list ≡ ([1,2],[3,4])"

definition bad_list :: "list2" where
  "bad_list ≡ ([1,2],[3,4,5])"

我可以定义一个单独的谓词,它检查一对列表是否正常:

definition list2_is_good :: "list2 ⇒ bool" where
  "list2_is_good x ≡ length (fst x) = length (snd x)"

value "list2_is_good good_list"
value "list2_is_good bad_list"

是否可以组合数据类型和谓词?我曾尝试使用inductive_set,但我不知道如何使用它:

inductive_set ind_list2 :: "(nat list × nat list) set" where
  "length (fst x) = length (snd x) ⟹
   x ∈ ind_list2"

2 个答案:

答案 0 :(得分:3)

您可以通过typedef创建一个受某个谓词约束的新类型,但结果只是type而不是datatype

typedef good_lists2 = "{xy :: list2. list2_is_good xy}" 
  by (intro exI[of _ "([],[])"], auto simp: list2_is_good_def)

使用这种新创建的类型最好通过提升包来完成。

setup_lifting type_definition_good_lists2

现在对于这个新的提升类型good_lists2的每个操作, 你有第一个 从原始类型list2解除操作。 例如,下面我们定义一个提取函数和一个Cons函数。 在后者中,您已经证明新生成的对确实满足不变量。

lift_definition get_lists :: "good_lists2 ⇒ list2" is "λ x. x" .

lift_definition Cons_good_lists2 :: "nat ⇒ nat ⇒ good_lists2 ⇒ good_lists2" 
  is "λ x y (xs,ys). (x # xs, y # ys)" 
  by (auto simp: list2_is_good_def)

当然,您也可以访问不变量 提升型。

lemma get_lists: "get_lists xy = (x,y) ⟹ length x = length y" 
  by (transfer, auto simp: list2_is_good_def)

我希望这会有所帮助。

答案 1 :(得分:2)

<>René的回答是你所要求的答案,但为了完整起见,我想补充两件事:

首先,在这里说明显而易见的事情:如果您只使用对列表而不是列表对,这似乎会容易得多。您建议的新类型显然与对列表同构。那么你不必引入额外的类型。

另外,更一般地说,仅仅因为可以在Isabelle中引入带有类型定义的新类型来捕获某些不变量并不意味着这总是最好的主意。单独携带不变量可能更容易。这在很大程度上取决于那些不变量的外观以及您对该类型的值实际执行的操作。在许多情况下,我认为用于设置新类型的额外样板(特别是如果需要那些类实例化)以及在基类型和新类型之间进行转换并不值得从中获得任何抽象优势。

我认为,一个好的启发式方法是问自己,你所介绍的类型是否更像是一个特定地方需要的“扔掉”的东西 - 然后不要为它引入新类型 - 或者是否可以证明一般事实并引入一个好的抽象理论 - 然后为它引入一种新的类型。后者分布的好例子是多集,有限集和概率质量函数。