类型 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
的构造函数的数据类型。但是,这是没有类型变量的非递归数据类型的非常简单的情况。对于您的表达式示例,我建议您执行以下操作:
用datatype expr_aux = Const_aux nat | Plus_aux expr_aux expr_aux
定义类型expr_aux
。
将 expr
定义为 expr_aux
和 typedef expr = "UNIV :: expr_aux set"
的类型副本。
用提升包将构造函数Const_aux
提升到expr
:lift_definition Const :: "nat => expr" is Const_aux .
实例化类型 class plus
:
instantiation expr :: plus begin
lift_definition plus_expr :: "expr => expr => expr" is Plus_aux .
instance ..
end
使用 old_rep_datatype expr Const "plus :: expr => _"
和适当的证明(使用 transfer
)将 expr
注册为数据类型。
定义一个abbreviation Plus :: "expr => expr => expr" where "Plus == plus"
显然,这很乏味。如果只想在函数中使用模式匹配,可以在实例化后使用free_constructor
命令将构造函数Const
和plus :: expr => expr => expr
注册为expr
的新构造函数。如果您随后添加 "Plus = plus" 作为简单规则,这应该几乎和乏味的方式一样好。然而,我不知道各种包(特别是 case 语法)如何处理构造函数的重新注册。
考虑这个 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
的构造函数的数据类型。但是,这是没有类型变量的非递归数据类型的非常简单的情况。对于您的表达式示例,我建议您执行以下操作:
用
datatype expr_aux = Const_aux nat | Plus_aux expr_aux expr_aux
定义类型expr_aux
。将
expr
定义为expr_aux
和typedef expr = "UNIV :: expr_aux set"
的类型副本。用提升包将构造函数
Const_aux
提升到expr
:lift_definition Const :: "nat => expr" is Const_aux .
实例化类型 class
plus
:
instantiation expr :: plus begin
lift_definition plus_expr :: "expr => expr => expr" is Plus_aux .
instance ..
end
使用
old_rep_datatype expr Const "plus :: expr => _"
和适当的证明(使用transfer
)将expr
注册为数据类型。定义一个
abbreviation Plus :: "expr => expr => expr" where "Plus == plus"
显然,这很乏味。如果只想在函数中使用模式匹配,可以在实例化后使用free_constructor
命令将构造函数Const
和plus :: expr => expr => expr
注册为expr
的新构造函数。如果您随后添加 "Plus = plus" 作为简单规则,这应该几乎和乏味的方式一样好。然而,我不知道各种包(特别是 case 语法)如何处理构造函数的重新注册。