I am trying to create a datatype with rules, so to speak, and I am unsure where to start (assuming it is possible!).
For example, I have a datatype, a pair (kind, value) defined as a record. I would like to define another datatype on top of it, a set of such records, with three rules: (1) the set is finite (2) at least one such a record must be in the set (3) only one record of each kind can be in the set
So, if I define them as:
datatype akind = k1 | k2 | k3
record apair =
kind :: akind
val :: nat
type_synonym aset = "apair set"
I would like to be able to limit aset such that s1, s2 are not "legal" aset, and s3 is.
define s1 :: aset where "s1 = {}"
define s2 :: aset where "s2 = {(k1, 1), (k1, 2)}
define s3 :: aset where "s3 = {(k1, 1), (k3, 3)}
How can I achieve this? I have definitely hit a block on this one. Thank you in advance!
In Isabelle/HOL, you can derive types from other types with a lot of freedom either by picking subsets of the type or by constructing quotient types. From your description, it sounds like you want to do something like the first, for which there is the
typedefcommand. (This would not be called “datatype” in the Isabelle/HOL sense. “datatypes” are “algebraic data types”, i.e., fancy kinds of (possibly infinitary) trees.)So, one would start out with an existing type that is a “superset” of what one wants to have. In your instance, I would say, we're talking about partial functions from
akindtonatwith the requirement that at least one kind is set to a value. (I'll glance over the requirement of finiteness asakindhas finitely many members anyways.) So, we'll embed intoakind ⇒ (nat option).Coming up with a set expressing the requirements
One starts out by expressing the type as a set on the base type:
We can now check that your first example indeed is not in this set, while the third one is. (And the second one is ruled out by using functions as a base.)
Deriving a type from a set
The second lemma shows that the set is non-empty. This is the only requirement we need to derive a new type from it. (In HOL, types must be non-empty!)
So, all done! What this does under the hood, is:
aset,Abs_aset:: (akind ⇒ nat option) ⇒ asetto “cast” functions as type members andRep_aset:: aset ⇒ akind ⇒ nat optionto get the function representing the type member.The pair of abstraction / representation functions is connected via some facts that allow you to go ”in circles” between the two views, as long as you stay within the
aset_setwe defined, in particular:Rep_aset_inverse: Abs_aset (Rep_aset ?x) = ?xAbs_aset_inverse: ?y ∈ aset_set ⟹ Rep_aset (Abs_aset ?y) = ?yfind_theorems Rep_aset!Working with derived types
We can now come up with the kinds of definitions we want by translating back and forth through
Rep_aset / Abs_asetand prove properties through their facts.For instance, we might want to define a
value_offunction to obtain the value associated with anakindand anupdatefunction to change it. We can prove useful properties on them:Why it might not help as much as one wants
The nice thing about types is to rule out bogus “values.“ The
Abs/Repapproach means that, whenever they appear, definitions might be meaningless. Nothing stops us from “defining” an unsafe function to remove assignments:Clearly, this definition seems to allow us to construct empty assignments---which we assumed to have ruled out in
aset_set! The trick here is that the axiomatization will not allow us to prove the facts we might desire:So, one has to keep the “invariants” in mind to come up with definitions that lead to anything nice to be provable.
Alternatives
In general, I recommend to only use
typedefas a last resort. Whenever you can express your models directly with existing types (ordatatypecombinations thereof), your life will be much nicer.Maybe, the invariant can just be carried around as a fact in the proofs where you really need it?
A middle ground is to use the
quotient_typeand just make redundant type members equal. For the example, one could start out with non-empty lists of key-value pairs and define an equivalence that only considers the first assignment appearing. However, this post already is getting quite long---so I'll leave it at this side-remark.