类型 class 实例化中的现有常量(例如构造函数)

Existing constants (e.g. constructors) in type class instantiations

考虑这个 Isabelle 代码

theory Scratch imports Main begin

datatype Expr = Const nat | Plus Expr Expr

实例化 plus 类型 class 以获得 Plus 构造函数的良好语法是非常合理的:

instantiation Expr :: plus
begin
  definition "plus_Exp = Plus"
instance..
end

但是现在,+Plus 仍然是独立的常量。特别是,我不能(轻易地)在函数定义中使用 +,例如

fun swap where
   "swap (Const n) = Const n"
 | "swap (e1 + e2) = e2 + e1"

将打印

Malformed definition:
Non-constructor pattern not allowed in sequential mode.
⋀e1 e2. swap (e1 + e2) = e2 + e1

如何使用 现有 常量实例化类型 class 而不是定义新常量?

Isabelle 中的 class 类型实例化总是为 class 类型的参数引入新常量。因此,你不能说 plus(写作中缀 +)与 Plus 相同。但是,您可以反过来,即先实例化类型 class,然后才将类型 class 上的操作声明为数据类型的构造函数。

在理论 Extended_Nat 中可以找到一个这样的例子,其中类型 enat 是通过 typedef 手动构造的,然后无限类型 class 被实例化,最后 enat 被声明为具有两个使用 old_rep_datatype 的构造函数的数据类型。但是,这是没有类型变量的非递归数据类型的非常简单的情况。对于您的表达式示例,我建议您执行以下操作:

  1. datatype expr_aux = Const_aux nat | Plus_aux expr_aux expr_aux定义类型expr_aux

  2. expr 定义为 expr_auxtypedef expr = "UNIV :: expr_aux set" 的类型副本。

  3. 用提升包将构造函数Const_aux提升到exprlift_definition Const :: "nat => expr" is Const_aux .

  4. 实例化类型 class plus:

instantiation expr :: plus begin
lift_definition plus_expr :: "expr => expr => expr" is Plus_aux .
instance ..
end
  1. 使用 old_rep_datatype expr Const "plus :: expr => _" 和适当的证明(使用 transfer)将 expr 注册为数据类型。

  2. 定义一个abbreviation Plus :: "expr => expr => expr" where "Plus == plus"

显然,这很乏味。如果只想在函数中使用模式匹配,可以在实例化后使用free_constructor命令将构造函数Constplus :: expr => expr => expr注册为expr的新构造函数。如果您随后添加 "Plus = plus" 作为简单规则,这应该几乎和乏味的方式一样好。然而,我不知道各种包(特别是 case 语法)如何处理构造函数的重新注册。