Why can't I apply a single step of a function like I do with definition in Isabelle? - isabelle

I'm trying to do:
datatype my_bool = true | false
value "true" (* it has value true with type my_bool *)
fun conj :: "my_bool ⇒ my_bool ⇒ my_bool" where
"conj true true = true" |
"conj _ _ = false"
lemma "conj true true = true"
apply (simp only: conj_def)
but I get error:
Undefined fact: "conj_def"⌂
I understand the error but not why I can't apply a single simp like I do with definitions. Is this possible with functions at all?

When you define a new constant using the command definition, a theorem like conj_def is provided automatically (actually, it is possible to control the name of this theorem). The command fun does not provide a theorem name_def automatically (where name is the name of the constant). However, it provides a variety of other theorems. You can see such theorems by typing print_theorems after the specification of a constant using the command fun. For example,
datatype my_bool = true | false
fun conj :: "my_bool ⇒ my_bool ⇒ my_bool"
where
"conj true true = true"
| "conj _ _ = false"
print_theorems
For example, in the code listing above the command fun provides the fact conj.simps, which is, most likely, what you were looking for:
lemma "conj true true = true"
by (simp only: conj.simps)
Technically, it is possible to recover the original definitional axioms in Isabelle/ML for any constant, including conj (some insight about the definitional principles can be gained from [1], but there could exist more specialized references for this):
theory Scratch
imports Main
keywords "get_da" :: diag
begin
ML‹
(*the implementation of axioms_of_ci and da_of_ci are based on elements of
the code HOL/Types_To_Sets/unoverloading.ML*)
local
fun match_args (Ts, Us) =
if Type.could_matches (Ts, Us)
then
Option.map Envir.subst_type
(
SOME (Type.raw_matches (Ts, Us) Vartab.empty)
handle Type.TYPE_MATCH => NONE
)
else NONE;
in
fun axioms_of_ci thy defs (c, T) =
let
val const_entry = Theory.const_dep thy (c, T);
val Uss = Defs.specifications_of defs (fst const_entry);
in
Uss
|> filter (fn spec => is_some (match_args (#lhs spec, snd const_entry)))
|> map (fn Us => (#def Us, #description Us))
end;
fun das_of_ci thy defs = axioms_of_ci thy defs
#> map #1
#> filter is_some
#> map (the #> try (Thm.axiom thy))
#> filter is_some
#> map (the #> Drule.abs_def);
end;
fun apdupr f x = (x, f x);
fun axioms_of_const ctxt (c, T) =
let
val thy = Proof_Context.theory_of ctxt
val defs = Theory.defs_of thy
in das_of_ci thy defs (c, T) end;
fun process_da t st =
let
val ctxt = Toplevel.context_of st
val const = t
|> Proof_Context.read_term_pattern ctxt
|> dest_Const
val _ = const
|> axioms_of_const ctxt
|> map (Thm.string_of_thm ctxt)
|> map writeln
in () end;
val tts_find_sbts = Outer_Syntax.command
\<^command_keyword>‹get_da›
"print definitional axioms"
(Parse.const >> (process_da #> Toplevel.keep));
›
datatype my_bool = true | false
fun conj :: "my_bool ⇒ my_bool ⇒ my_bool"
where
"conj true true = true"
| "conj _ _ = false"
print_theorems
lemma "conj true true = true"
by (simp only: conj.simps)
get_da conj_graph
get_da conj_sumC
get_da conj
text‹The type of the input to the command #{command get_da} is important:›
get_da ‹plus::nat⇒nat⇒nat›
get_da ‹plus::int⇒int⇒int›
end
However, as noted by Manuel Eberl in the comments, such axioms are not particularly useful for most practical purposes for the end users.
Isabelle version: Isabelle2020
References:
Haftmann F, Wenzel M. Local Theory Specifications in Isabelle/Isar. In: Berardi S, Damiani F, de’Liguoro U, editors. Types for Proofs and Programs. Heidelberg: Springer; 2009. p. 153–68.

Related

Add `example` as an Isar synonym for `lemma`

In my Isabelle/HOL theories, I like using unnamed lemmas as examples.
Here is an example how some of my theories look like.
definition foo_function :: "nat ⇒ nat" where "foo_function x = x+1"
text‹Example:›
lemma "foo_function 3 = 4" by eval
I feel the whole theory would read much nicer if I have an example keyword, which is basically equivalent to an unnamed lemma. Here is what I would like to write:
definition foo_function :: "nat ⇒ nat" where "foo_function x = x+1"
example "foo_function 3 = 4" by eval
Is there a super simple and stable way to set this up?
Control-click on lemma (besides proofs, this is the most important feature in Isabelle. Really. You can control-click on nearly everything to understand how it is defined) and copy-pasting the setup:
theory Scratch
imports Main
keywords "example" :: thy_goal_stmt
begin
ML ‹
local
val long_keyword =
Parse_Spec.includes >> K "" ||
Parse_Spec.long_statement_keyword;
val long_statement =
Scan.optional (Parse_Spec.opt_thm_name ":" --| Scan.ahead long_keyword) Binding.empty_atts --
Scan.optional Parse_Spec.includes [] -- Parse_Spec.long_statement
>> (fn ((binding, includes), (elems, concl)) => (true, binding, includes, elems, concl));
val short_statement =
Parse_Spec.statement -- Parse_Spec.if_statement -- Parse.for_fixes
>> (fn ((shows, assumes), fixes) =>
(false, Binding.empty_atts, [], [Element.Fixes fixes, Element.Assumes assumes],
Element.Shows shows));
fun theorem spec schematic descr =
Outer_Syntax.local_theory_to_proof' spec ("state " ^ descr)
((long_statement || short_statement) >> (fn (long, binding, includes, elems, concl) =>
((if schematic then Specification.schematic_theorem_cmd else Specification.theorem_cmd)
long Thm.theoremK NONE (K I) binding includes elems concl)));
val _ = theorem \<^command_keyword>‹example› false "example";
in end
›
example True
by eval
end

Writing variable patterns in Isabelle/ML

I was studying ways to trasnlate:
apply(rewrite in "_ / ⌑" some_theorem)
into ML, and I came up with the following:
apply(tactic ‹
let
val pat = [
Rewrite.In,
Rewrite.Term (#{const divide(real)} $ Var (("c", 0), \<^typ>‹real›) $
Rewrite.mk_hole 1 (\<^typ>‹real›), []),
Rewrite.In
]
val to = NONE
in
CCONVERSION (Rewrite.rewrite_conv #{context} (pat, to) #{thms juanito_def}) 1
end
›)
here I am saying "please pattern match with any subterm of the term in the quotient". You may see previous edits of the question to see interesting patterns.
Some interesting conclusions of having used the library are
at : allows to select a subterm in which to pattern match
in : allows to specify all the subterms of a term
terms will be pattern-matched with the resulting patterns.
Not understood
Could you give an explanation of what the following tactic is doing?
lemma
assumes "Q (λb :: int. P (λa. a + b) (λa. a + b))"
shows "Q (λb :: int. P (λa. a + b) (λa. b + a))"
apply (tactic ‹
let
val (x, ctxt) = yield_singleton Variable.add_fixes "x" \<^context>
val pat = [
Rewrite.Concl,
Rewrite.In,
Rewrite.Term (Free ("Q", (\<^typ>‹int› --> TVar (("'b",0), [])) --> \<^typ>‹bool›)
$ Abs ("x", \<^typ>‹int›, Rewrite.mk_hole 1 (\<^typ>‹int› --> TVar (("'b",0), [])) $ Bound 0), [(x, \<^typ>‹int›)]),
Rewrite.In,
Rewrite.Term (#{const plus(int)} $ Free (x, \<^typ>‹int›) $ Var (("c", 0), \<^typ>‹int›), [])
]
val to = NONE
in CCONVERSION (Rewrite.rewrite_conv ctxt (pat, to) #{thms add.commute}) 1 end
›)
apply (fact assms)
done
The first Rewrite.Term and the fixing of a variable are a bit obscure to me.

Wellsortedness error ... not of sort equal

Here is a trivial translator from language foo to bar:
type_synonym vname = "string"
type_synonym 'a env = "vname ⇒ 'a option"
datatype foo_exp = FooBConst bool
datatype foo_type = FooBType | FooIType | FooSType
datatype bar_exp = BarBConst bool
datatype bar_type = BarBType | BarIType
fun foo_to_bar_type :: "foo_type ⇒ bar_type option" where
"foo_to_bar_type FooBType = Some BarBType" |
"foo_to_bar_type FooIType = Some BarIType" |
"foo_to_bar_type _ = None"
inductive foo_to_bar :: "foo_type env ⇒ foo_exp ⇒ bar_type env ⇒ bar_exp ⇒ bool" where
"Γ⇩B = map_comp foo_to_bar_type Γ⇩F ⟹
foo_to_bar Γ⇩F (FooBConst c) Γ⇩B (BarBConst c)"
code_pred [show_modes] foo_to_bar .
values "{t. foo_to_bar Map.empty (FooBConst True) Map.empty t}"
The last line causes the following error:
Wellsortedness error
(in code equation foo_to_bar_i_i_i_o ?x ?xa ?xb ≡
Predicate.bind (Predicate.single (?x, ?xa, ?xb))
(λ(Γ⇩F_, aa, Γ⇩B_).
case aa of
FooBConst c_ ⇒
Predicate.bind (eq_i_i Γ⇩B_ (foo_to_bar_type ∘⇩m Γ⇩F_))
(λ(). Predicate.single (BarBConst c_))),
with dependency "Pure.dummy_pattern" -> "foo_to_bar_i_i_i_o"):
Type char list ⇒ bar_type option not of sort equal
No type arity list :: enum
Could you suggest me how to fix it?
Also foo_to_bar has mode i => i => o => o => boolpos. How should I execute values to generate both 3rd and 4th arguments?
In general I'd advise against using inductive to define something that can easily be expressed as a function. While the predicate compiler comes with a lot of bells and whistles to make computational sense of an inductive definition, there are a lot of problems that can arise because it's so complex. In your case, the problem lies in the line
Γ⇩B = map_comp foo_to_bar_type Γ⇩F
You are trying to compare two functions. The predicate compiler doesn't know that it can be seen as a "defining equation". In a sense, you're asking the predicate compiler to solve an impossible problem.
Your life will be much easier if foo_to_bar is defined as a function (or plain definition) instead. It'll work out of the box with the code generator.

Are constructors in the plain calculus of constructions disjoint and injective?

Based on this answer, it looks like the calculus of inductive constructions, as used in Coq, has disjoint, injective constructors for inductive types.
In the plain calculus of constructions (i.e., without primitive inductive types), which uses impredicative encodings for types (e.g., ∏(Nat: *).∏(Succ: Nat → Nat).∏(Zero: Nat).Nat), is this still true? Can I always find out which "constructor" was used? Also, is injectivity (as in ∀a b.I a = I b → a = b) provable in Coq with Prop or impredicative Set?
This seems to cause trouble in Idris.
(I am not sure about all the points that you asked, so I am making this answer a community wiki, so that others can add to it.)
Just for completeness, let's use an impredicative encoding of the Booleans as an example. I also included the encodings of some basic connectives.
Definition bool : Prop := forall (A : Prop), A -> A -> A.
Definition false : bool := fun A _ Hf => Hf.
Definition true : bool := fun A Ht _ => Ht.
Definition eq (n m : bool) : Prop :=
forall (P : bool -> Prop), P n -> P m.
Definition False : Prop := forall (A : Prop), A.
We cannot prove that true and false are disjoint in CoC; that is, the following statement is not provable:
eq false true -> False.
This is because, if this statement were provable in CoC, we would be able to prove true <> false in Coq, and this would contradict proof irrelevance, which is a valid axiom to add. Here is a proof:
Section injectivity_is_not_provable.
Variable Hneq : eq false true -> False. (* suppose it's provable in CoC *)
Lemma injectivity : false <> true.
Proof.
intros Heq.
rewrite Heq in Hneq.
now apply (Hneq (fun P x => x)).
Qed.
Require Import Coq.Logic.ProofIrrelevance.
Fact contradiction : Logic.False.
Proof.
pose proof (proof_irrelevance bool false true) as H.
apply (injectivity H).
Qed.
End injectivity_is_not_provable.

CARD of typedef of 0 to 7 nat

Update 2 (151015)
I put some source below. It shows a skeleton of what I may use.
With some help, I'm getting more sophisticated. I now know the difference between a numeral type type, and a constant of type numeral. The notation is all the same, and I'm used to using functions that operate on terms, not types. With CARD, that changes the paradigm some.
As far as numeral type notation, even with show_consts, it's not obvious that I'm looking at a type or a term. So, I draw off always using show_sorts and show_consts. A 0-ary type constructor type, like nat, never gets annotated with anything. Knowing that helps.
I said that a certain theorem wasn't being proved by magic without not importing Numeral_Type, but that's not true.
Succinct syntax is important, so getting good type inference is important. It looks like I get good type inference when using the numeral type.
From the answer, I also got my first use of using a dummy type, which, at this point, appears to be a much better way to do things.
Here's some source:
theory i151013c_numeral_has_type_enforcement
imports Complex_Main "~~/src/HOL/Library/Numeral_Type"
begin
declare [[show_sorts, show_consts]]
datatype ('a,'size) vD = vC "'a list"
definition CARD_foo :: "('a,'s::{finite,card_UNIV}) vD => ('a,'s) vD => nat"
where
"CARD_foo x y = card (UNIV :: 's set)"
notation (input) vC ("vC|_" [1000] 1000)
notation (output) vC ("vC|_" [1000] 999)
value "CARD_foo (vC|x::(nat,32) vD) vC|y = (32::nat)" (*True*)
value "CARD_foo (vC|x::(nat,65536) vD) vC|y = 65536" (*True*)
type_synonym nv3 = "(nat, 3) vD"
notation CARD_foo (infixl "*+*" 65)
value "vC|m *+* (vC|n::nv3) = 3" (*True*)
type_notation (input) vD ("< _ , _ >")
term "x::<'a,'s::{finite,card_UNIV}>"
term "vC|m *+* (vC|n::<'a,64>) = 64"
value "vC|m *+* (vC|n::<'a,64>) = 64" (*True*)
(*Next, Am I adding 2 types of type numeral? Or am I adding 2 constants of
type numeral, which produces a numeral type? The notation for numeral types
and numeral type constants is identical.*)
value "vC|[3] *+* (vC|y::<nat,2 + 3>)"
term "vC|[3] *+* (vC|y::<nat,2 + 3>)"
(*I guess 2 and 3 are types. In the output panel, 0-ary types, such as 'nat',
don't get annotated with anything, where nat constants do.*)
lemma "vC|[3] *+* (vC|y::<nat,2 + 3>) = 5"
by(simp add: CARD_foo_def)
(*Type error clash. Oh well. Just don't do that.*)
term "(vC|x::<'a,5>) *+* (vC|y::<'a,2 + 3>)"
definition vCARD :: "('a, 's::{finite,card_UNIV}) vD => nat" where
"vCARD x = CARD('s)"
declare vCARD_def [simp add]
lemma
"vCARD(x::<'a,'s::{finite,card_UNIV}>) =
vCARD(y::<'b,'s::{finite,card_UNIV}>)"
by(simp)
end
Update (151014)
Here I explain to M.Eberl why I don't use the numeral type, based upon what I know and have experienced.
Related comment about typedef and a past question
A while back, I got exposed to ~~/src/HOL/Library/Cardinality, along with Numeral_Type from this answer by M.Eberl:
Trying to generalize a bit vector that uses typedef, bool list, and nat length
That question was also related to typedef. Partly from my experiments at that time, I try to stay away from typedef, and use the magic that comes with datatype.
Even today, I started having problems with the sz8 typedef not working with value, because of abstraction problems. After looking back at the answer linked to above, it partially shows what has to be done to get typedef working with value. I have a size8 in the new source I include that shows what I did. I think there's a problem with the equal function, that it needs to be fixed similar to what's shown in the answer above.
An Example size datatype and vector datatype
Now, I make a few comments about the two example datatypes in the second source I include below.
The use case for a size type is for vector length, where the vectors are lists.
The size type enforces that for a binary operation, two vectors have the same length. I then only have to check that the two vectors actually are the right length.
The problem with the numeral type is that there's no type enforcement. My example function has the following signature, with the datatype shown:
datatype ('a,'size) vD = vC "'a list" 'size
CARD_foo :: "(nat,'s::card_UNIV) vD => (nat,'s) vD => nat"
But I can to this:
term "CARD_foo (vC [] 10) (vC [] 11)"
Other comments are in the source. I have a typedef size8 at the end, and I don't know, at this time, how to fix that.
Though there's no type enforcement with the numeral type, I guess I can depend on type size using CARD, based on this:
theorem CARD_of_type_of_terms_of_same_type_are_equal:
"CARD_foo (vC n size1term) = CARD_foo (vC m size2term)"
unfolding CARD_foo_def
by(auto simp add: CARD_foo_def)
To get that by magic, I had to not import "~~/src/HOL/Library/Numeral_Type".
Thanks for the help. It's invaluable, and thanks for how to get the proofs I asked for originally. It helps to learn things here and there about typedef.
The new example source:
theory i151013b_2nd
imports Complex_Main (*"$GEZ/e/IsE"*)
"~~/src/HOL/Library/Cardinality" "~~/src/HOL/Library/Numeral_Type"
begin
declare [[show_sorts, show_consts]]
(*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*)
(*::¦ NUMERAL TYPE DOESN'T GUARANTEE TYPE ENFORCEMENT FOR A BINARY OP ¦:::*)
(*----------------------------*)
(*The size type as a datatype.*)
datatype sz8D = sz8C bool bool bool
(*-----------------------------------*)
(*Typdef 'n <= 7 would be preferable.*)
lemma UNIV_sz8D:
"UNIV =
{sz8C False False False, sz8C False False True, sz8C False True False,
sz8C False True True, sz8C True False False, sz8C True False True,
sz8C True True False, sz8C True True True}"
by(auto, metis (full_types) sz8D.exhaust)
lemma card_UNIV_sz8D [simp]: "card (UNIV :: sz8D set) = 8"
by(unfold UNIV_sz8D, auto)
instantiation sz8D :: card_UNIV
begin
definition "finite_UNIV = Phantom(sz8D) True"
definition "card_UNIV = Phantom(sz8D) 8"
instance
apply(default)
unfolding UNIV_sz8D finite_UNIV_sz8D_def card_UNIV_sz8D_def
by(auto)
end
(*-----------------------------------------*)
(*The vector type with an example function.*)
datatype ('a,'size) vD = vC "'a list" 'size
definition CARD_foo :: "(nat,'s::card_UNIV) vD => (nat,'s) vD => nat" where
"CARD_foo x y = card (UNIV :: 's set)"
thm CARD_foo_def
(*--------------------------------------------------------*)
(*sz8D: Size enforcement. Error if I mix other size types.*)
value "CARD_foo (vC [] (s::sz8D)) (vC [1] (t::sz8D))" (*outputs 8*)
value "CARD_foo (vC [] (sz8C False False False)) (vC [1] (t::sz8D))"
(*-------------------------------------*)
(*numeral: No enforcement of size type.*)
term "CARD_foo (vC [] 10) (vC [] 11)" (*
"CARD_foo (vC [] (10::'a::{card_UNIV,numeral}))
(vC [] (11::'a::{card_UNIV,numeral}))" :: "nat" *)
(*Can't eval the type to nat, even if they're the same*)
value "CARD_foo (vC [] 10) (vC [] 10)"
(*But here, CARDs are different anyway; no enforcement, no value.*)
value "CARD_foo (vC [] 10) (vC [] 11)" (*
"of_phantom card_UNIV_class.card_UNIV" :: "nat"*)
lemma "CARD_foo (vC [] 10) (vC [] 11) = z" oops (*
show_consts:
CARD_foo (vC [] (10::'a)) (vC [] (11::'a)) = z
'a :: {card_UNIV,numeral} *)
(*Can evaluate when there's not a conflict.*)
term "CARD(10)"
value "CARD(10)" (*outputs 10*)
lemma "CARD(10) = 10" by simp (*show_consts: 'UNIV :: 10 set'*)
value "CARD(11)" (*outputs 11*)
(*No eval if CARD('a) is used in a function.*)
definition fooID :: "'a::card_UNIV => nat" where
"fooID x = CARD('a)"
term "fooID(5)"
value "fooID(5)"
(*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*)
(*::¦ HOWEVER, BY FUNCTION UNIQUENESS, I SUPPOSE THERE'S NO AMBIGUITY ¦:::*)
(*[>) I have to drop down to only 'src/HOL/Library/Cardinality' to get this.
[>) For some reason, it won't unfold the definition.*)
theorem CARD_of_type_of_terms_of_same_type_are_equal:
"CARD_foo (vC n size_1term) = CARD_foo (vC m size_2term)"
unfolding CARD_foo_def
by(auto simp add: CARD_foo_def)
(*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*)
(*::¦ CAN'T USE TYPEDEF AFTERALL IF I CAN'T FIX THIS ¦::::::::::::::::::::*)
(*NOTE ABOUT PLUG'N'PLAY:
[>) See http://stackoverflow.com/q/27415275
[>) 'value' for 'CARD_foo' needs class 'equal'
[>) '[code abstract]' didn't work, so I used '[code]'.*)
typedef size8 = "{n::nat. n ≤ 7}"
morphisms size8_to_nat Abs_size8
by(blast)
definition nat_to_size8 :: "nat => size8" where
"nat_to_size8 n == if n ≤ 7 then Abs_size8 n else Abs_size8 0"
lemma nat_to_size8_code [code]:
"size8_to_nat (nat_to_size8 n) = (if n ≤ 7 then n else 0)"
unfolding nat_to_size8_def
by(simp add: Abs_size8_inverse)
setup_lifting type_definition_size8
instantiation size8 :: equal
begin
lift_definition equal_size8 :: "size8 => size8 => bool" is "λx y. x = y" .
instance
by(default, transfer, auto simp add: equal_size8_def)
end
instantiation size8 :: card_UNIV
begin
definition "finite_UNIV = Phantom(size8) True"
definition "card_UNIV = Phantom(size8) 8"
instance sorry
end
value "CARD_foo (vC [] (Abs_size8 0)) (vC [] (Abs_size8 0))" (*
Abstraction violation: constant Abs_size8 *)
end
Original Question
I'm using typedef to define some types that are used as size types, to be used like this: CARD(sz8). I can use datatype, but it takes a lot longer for it to set itself up.
I guess I don't understand how to show two values are unique with the inverse theorems generated by typedef for sz8.
I have my type, sz8, and I instantiate it as card_UNIV. What's incomplete is my theorem card_UNIV_sz8, which is "card (UNIV::sz8 set) = 8".
theory i151013a
imports Complex_Main "~~/src/HOL/Library/Cardinality"
"$GEZ/e/IsE"
begin
declare [[show_sorts, show_consts]]
typedef sz8 = "{n::nat. n ≤ 7}"
by(blast)
theorem UNIV_sz8:
"UNIV = {s::sz8. ∃n. n ≤ 7 ∧ s = Abs_sz8 n}"
using Rep_sz8 Rep_sz8_inverse
by(fastforce)
theorem foo1:
assumes "Abs_sz8 n ∈ {s::sz8. ∃n ≤ 7. s = Abs_sz8 n}"
shows "n ∈ {n. n ≤ 7}"
proof
fix n :: nat
note assms
obtain n1 where
f1: "n1 ≤ (7::nat) ∧ Abs_sz8 n = Abs_sz8 n1"
using Rep_sz8 Rep_sz8_inverse
by(fastforce)
hence "n = n1"
oops
find_theorems name: "sz8"
instance sz8 :: finite
apply default
unfolding UNIV_sz8
by(simp)
theorem card_UNIV_sz8 [simp]:
"card (UNIV::sz8 set) = 8"
unfolding UNIV_sz8
sorry
instantiation sz8 :: card_UNIV
begin
definition "finite_UNIV = Phantom(sz8) True"
definition "card_UNIV = Phantom(sz8) 8"
instance
apply default
unfolding finite_UNIV_sz8_def card_UNIV_sz8_def
by(simp_all)
end
end
The answer to your question
First of all: I will answer your question, but then I will tell you why what you are doing is unnecessary.
You can show the distinctness of the values using the theorem sz8.Abs_sz8_inject, which shows up if you do find_theorems Abs_sz8:
(?x::nat) ∈ {n::nat. n ≤ (7::nat)} ⟹
(?y::nat) ∈ {n::nat. n ≤ (7::nat)} ⟹
(Abs_sz8 ?x = Abs_sz8 ?y) = (?x = ?y)
You can prove your theorem e.g. like this:
lemma sz8_image: "x ∈ Abs_sz8 ` {0..7}"
by (cases x rule: sz8.Abs_sz8_cases) auto
theorem card_UNIV_sz8 [simp]: "card (UNIV::sz8 set) = 8"
proof -
from sz8_image have "UNIV = Abs_sz8 ` {0..7}" by blast
also from sz8.Abs_sz8_inject have "card … = card {0..(7::nat)}"
by (intro card_image inj_onI) simp_all
finally show ?thesis by simp
qed
What you should do instead
Have a look at the theory ~~/src/HOL/Library/Numeral_Type, where ~~ stands for the Isabelle root directory.
This defines a type n for every positive integer n, which contains exactly the numbers from 0 to n - 1 and even defines lots of typeclass instances and modular arithmetic on them. For example:
value "(2 - 5 :: 10) = 7"
> "True" :: "bool"
This is probably exactly what you want and it comes fully set up; doing all of this by hand is quite tedious, and if you ever need a size 16 type, you have to do the same thing all over again.
Update: More on numeral types
In your updated question, you claim that type checking for numeral types does not work. That is not correct; the problem is merely that the 10 in your vC [] 10 has no meaning. Your intention was probably to specify that the length parameter 'size in the type of that function must be 10.
However, every numeral type contains a 10. For instance, (10 :: 5) = 0 and (10 :: 6) = 4. Therefore, the 10 and 11 in there do not cause any type restrictions at all.
What you have to do is constrain 'size at the type level:
datatype ('a,'size) vD = vC "'a list"
consts CARD_foo :: "(nat,'s::card_UNIV) vD => (nat,'s) vD => nat"
term "CARD_foo (vC [] :: (nat, 10) vD) (vC [] :: (nat, 11) vD)"
(* Type error *)
If you really want to do something on the value-level similar to what you tried to do, you can use the following trick:
datatype ('a,'size) vD = vC "'a list" "'size itself"
consts CARD_foo :: "(nat,'s::card_UNIV) vD => (nat,'s) vD => nat"
term "CARD_foo (vC [] TYPE(10)) (vC [] TYPE(11))"
'a itself is basically a singleton type that contains the value TYPE('a). I think the variant without these itself values is probably more convenient in the long run though.
As for why your CARD_of_type_of_terms_of_same_type_are_equal does not work, I cannot say without seeing the definition of the constants involved, I am quite sure that everything that works with your hand-crafted sz8 type will work with numeral types.
At the end of the day, you can always replace sz8 everywhere in your code with 8 and everything should still work.

Resources