问题
Consider this Isabelle code
theory Scratch imports Main begin
datatype Expr = Const nat | Plus Expr Expr
it is quite reasonable to instantiate the plus type class to get nice syntax for the Plus constructor:
instantiation Expr :: plus
begin
definition "plus_Exp = Plus"
instance..
end
But now, + and Plus are still separate constants. In particular, I cannot (easily) use + in a function definition, e.g.
fun swap where
"swap (Const n) = Const n"
| "swap (e1 + e2) = e2 + e1"
will print
Malformed definition:
Non-constructor pattern not allowed in sequential mode.
⋀e1 e2. swap (e1 + e2) = e2 + e1
How can I instantiate a type class with an existing constant instead of defining a new one?
回答1:
Type class instantiations in Isabelle always introduce new constants for the parameters of the type class. Thus, you cannot say that plus (written infix as +) shall be the same as Plus. However, you can go the other way around, namely instantiate the type class first and only later declare the operations on the type class as the constructors of the datatype.
One such case can be found in the theory Extended_Nat where the type enat is constructed manually via a typedef, then the infinity type class is instantiated, and finally enat is declared as a datatype with two constructors using old_rep_datatype. However, this is a very simple case of a non-recursive datatype without type variables. In case of your expression example, I recommend that you do the following:
Define a type
expr_auxwithdatatype expr_aux = Const_aux nat | Plus_aux expr_aux expr_aux.Define a
expras a type copy ofexpr_auxwithtypedef expr = "UNIV :: expr_aux set"andsetup_lifting type_definition_expr.Lift the constructor
Const_auxtoexprwith the lifting package:lift_definition Const :: "nat => expr" is Const_aux .Instantiate the type class
plus:
instantiation expr :: plus begin
lift_definition plus_expr :: "expr => expr => expr" is Plus_aux .
instance ..
end
Register
expras a datatype withold_rep_datatype expr Const "plus :: expr => _"and an appropriate proof (usetransfer).Define an
abbreviation Plus :: "expr => expr => expr" where "Plus == plus"
Obviously, this is very tedious. If you just want to use pattern matching in functions, you can use the free_constructor command to register the constructors Const and plus :: expr => expr => expr as new constructors of expr after the instantiation. If you then add "Plus = plus" as a simp rule, this should be almost as good as the tedious way. Yet, I do not know how well the various packages (in particular case syntax) cope with this re-registration of the constructors.
来源:https://stackoverflow.com/questions/30759140/existing-constants-e-g-constructors-in-type-class-instantiations