I investigated Coq a little, with its dependent types. I have only the foggiest idea about it all, but now I have in mind that I want a bit vector as a bool list
, in which the length of the vector is part of the type.
(This question is the possible predecessor of another question. In the next question, if I ask it, I'll ask whether I can recover what I lose, when I use typedef
as below.)
(For this question, the question is at the bottom)
Here are the requirements for the type I want:
- It has to use
bool list
, so that I can directly or indirectly do pattern matching and recursion on the list, and - the length of the vector has to be specified in the type.
Here is what I have:
typedef bitvec_4 = "{bl::bool list. length bl = 4}"
by(auto, metis Ex_list_of_length)
It's important that the length of the list be part of the type, because I want to use the type with a definition
, where all lists are known to be of the same size, like with this simple example:
definition two_bv4_to_bv4 :: "bitvec_4 => bitvec_4 => bitvec_4" where
"two_bv4_to_bv4 x y = x"
What I don't want, in a theorem, is to have to specify the length of the lists. Type classes would eventually come into play somehow, but I want, as I say, the length to be specified in the type definition.
Definition and type signatures. Where do I let n = 4
!!? (a tech joke of minimal humor-value)
Now, I try to generalize with a typedef
like this, in which the length is a variable:
typedef bitvec_n = "{(bl::bool list, n::nat). length bl = n}"
by(auto)
That's no good. In a definition like this next one, my type doesn't guarantee that all lists are of the same length:
definition two_bvn_to_bvn :: "bitvec_n => bitvec_n => bitvec_n" where
"two_bvn_to_bvn x y = x"
The question? (I think so)
I've experimented a little with types like bitvec_4
above. If I don't run into big roadblocks, I might try to make big use of them.
I could define types like the above for powers of 2, up to, say, 1024 bits, along with type classes that reflect their common properties.
But, is there a better way to do this? It has to be somewhat straightforward, I think, with the use of bool list
.
Update (got the answer for what it was actually about)
Based on Manuel's answer, I include here a self-contained theory.
It's mostly a duplication of Manuel's source, but at the end, my functions swap_bl
and swap_2bv
, along with the final use of value
, show the end result of what I was trying to accomplish. My comments emphasize the problems that were on my mind, and possibly, my end application shows why I haven't looked to HOL/Word
as a solution.
For a typedef
type, to do pattern matching indirectly, similar to that with swap_bl
and 2 bitvec
, I was using the Abs
and Rep
functions together as inverses. One problem, as Manuel pointed out, is that I can feed an Abs
function a bool list
of the wrong length, and it won't give an error. Another big problem is the abstraction violations due to the use of the Abs
function.
Those problems, and wanting to know if I could recover the use of value
for my typedef
type, would have been parts of my next question, but all that's been answered here.
theory i141210ac__testing_out_manuels_answer
imports Main "~~/src/HOL/Library/Numeral_Type"
begin
(*Basic type definition.*)
typedef ('n::finite) bitvec = "{bs :: bool list. length bs = CARD('n)}"
morphisms bitvec_to_list Abs_bitvec
by (simp add: Ex_list_of_length)
setup_lifting type_definition_bitvec
lift_definition nth :: "('n::finite) bitvec => nat => bool" (infixl "$" 90)
is List.nth .
(*Can't use 'value' yet for 'nth', or I get an abstraction violation.*)
term "(Abs_bitvec [True,False] :: 2 bitvec) $ 1"
(*Truncate or fill the list: needed to set things up for 'value'.*)
definition set_length :: "nat => bool list => bool list" where
"set_length n xs = (if length xs < n
then xs @ replicate (n - length xs) False
else take n xs)"
lemma length_set_length [simp]: "length (set_length n xs) = n"
unfolding set_length_def by auto
definition list_to_bitvec :: "bool list => ('n::finite) bitvec" where
"list_to_bitvec xs = Abs_bitvec (set_length CARD('n) xs)"
(*Finishing the magic needed for 'value'.*)
lemma list_to_bitvec_code [code abstract]:
"bitvec_to_list (list_to_bitvec xs :: ('n::finite) bitvec)
= set_length CARD('n) xs"
unfolding list_to_bitvec_def by(simp add: Abs_bitvec_inverse)
(*Inverses for lists of length 2: no abstraction violations.*)
value "list_to_bitvec (bitvec_to_list x) :: 2 bitvec"
value "bitvec_to_list (list_to_bitvec x :: 2 bitvec)"
(*The magic now kicks in for 'value' and 'nth'. Understanding is optional.*)
value "(list_to_bitvec [True,False] :: 2 bitvec) $ 1" (*OUTPUT: False.*)
(*For my use, the primary context of all this is pattern matching on lists.
I can't pattern match on a 'typedef' type directly with 'fun', because
it's not a 'datatype'. I do it indirectly.*)
fun swap_bl :: "bool list => bool list" where
"swap_bl [a,b] = [b,a]"
|"swap_bl _ = undefined"
definition swap_2bv :: "2 bitvec => 2 bitvec" where
"swap_2bv bv = list_to_bitvec (swap_bl (bitvec_to_list bv))"
value "swap_2bv (list_to_bitvec [a,b] :: 2 bitvec)" (*
OUTPUT: "Abs_bitvec [b, a]" :: "2 bitvec" *)
(*Whether that's all a good idea, that's about the future, but it appears the
hard work, recovering the use of 'value', along with generalizing length,
has been done by Manuel, and the authors of Numeral_Type and its imports.*)
end
Isabelle does not support dependent types, but there are ways to still do what you want to do. For instance, there is already a stack of type classes and type syntax for type-level natural numbers.
theory Scratch
imports Main "~~/src/HOL/Library/Numeral_Type"
begin
lemma "(UNIV :: 4 set) = {0,1,2,3}"
by (subst UNIV_enum) eval
As you can see, the type 4
is a type that contains the numbers from 0
to 3
. Incidentally, this can also be used for computations in modular arithmetic:
lemma "((2 + 3) :: 4) = 1" by simp
lemma "((2 * 3) :: 4) = 2" by simp
You can use these numeral types to parametrise your bit vectors with a length:
typedef ('n::finite) bitvec = "{bs :: bool list. length bs = CARD('n)}"
morphisms bitvec_to_list Abs_bitvec
by (simp add: Ex_list_of_length)
setup_lifting type_definition_bitvec
You can access the n-th element of a bit vector by lifting the nth
function from Boolean lists to bit vectors, which works automatically:
lift_definition nth :: "('n::finite) bitvec ⇒ nat ⇒ bool" (infixl "$" 90) is List.nth .
Converting boolean lists to bit vectors is a bit tricky, because the list you get in might not have the correct length; the expression list_to_bitvec [True] :: 2 bitvec
would typecheck, but is obviously problematic. You could solve this either by returning undefined
or, perhaps more appropriate in this instance, filling up the list with False
or truncating it to get the right length:
definition set_length :: "nat ⇒ bool list ⇒ bool list" where
"set_length n xs = (if length xs < n then xs @ replicate (n - length xs) False else take n xs)"
lemma length_set_length[simp]: "length (set_length n xs) = n"
unfolding set_length_def by auto
Now we can define a function that converts a list of Booleans to a bit vector:
definition list_to_bitvec :: "bool list ⇒ ('n::finite) bitvec" where
"list_to_bitvec xs = Abs_bitvec (set_length CARD('n) xs)"
However, we are not allowed to use Abs_bitvec
in code equations; if you tried to evaluate, say, list_to_bitvec [True] :: 1 bitvec
, you would get an abstraction violation. We have to give an explicit code abstract equation in terms of the morphism list_to_bitvec
:
lemma list_to_bitvec_code[code abstract]:
"bitvec_to_list (list_to_bitvec xs :: ('n::finite) bitvec) = set_length CARD('n) xs"
unfolding list_to_bitvec_def by (simp add: Abs_bitvec_inverse)
And now we are basically done and can do e.g. this:
definition myvec :: "4 bitvec" where "myvec = list_to_bitvec [True, False, True]"
value myvec
(* Output: "Abs_bitvec [True, False, True, False]" :: "4 bitvec" *)
value "myvec $ 2"
(* Output: "True" :: "bool" *)
Note that you always have to annotate the result of list_to_bitvec
with its length; Isabelle can not infer the length.
You may also want to have a look at the Word
theory in ~~/src/HOL/Word/
; it implements machine words of fixed length with all kinds of bit operations like NOT
, AND
, OR
, etc.:
value "42 AND 23 :: 32 word"
(* Output: "2" :: "32 word" *)
value "293 :: 8 word"
(* Output: "37" :: "8 word" *)
value "test_bit (42 :: 8 word) 1"
(* Output: "True" :: "bool" *)
value "set_bit (42 :: 8 word) 2 True"
(* Output: "46" :: "8 word" *)
value "(BITS i. i < 4) :: 8 word"
(* Output: "15" :: "8 word" *)
Another related type are the vectors in src/HOL/Library/Multivariate_Analysis/Finite_Cartesian_Product
.
来源:https://stackoverflow.com/questions/27415275/trying-to-generalize-a-bit-vector-that-uses-typedef-bool-list-and-nat-length