问题
I would love to generate code from locale
definitions directly, without interpretation. Example:
(* A locale, from the code point of view, similar to a class *)
locale MyTest =
fixes L :: "string list"
assumes distinctL: "distinct L"
begin
definition isInL :: "string => bool" where
"isInL s = (s ∈ set L)"
end
The assumptions to instantiate MyTest
are executable and I can generate code for them
definition "can_instance_MyTest L = distinct L"
lemma "can_instance_MyTest L = MyTest L"
by(simp add: MyTest_def can_instance_MyTest_def)
export_code can_instance_MyTest in Scala file -
I can define a function to execute the isInL
definition for arbitrary MyTest
.
definition code_isInL :: "string list ⇒ string ⇒ bool option" where
"code_isInL L s = (if can_instance_MyTest L then Some (MyTest.isInL L s) else None)"
lemma "code_isInL L s = Some b ⟷ MyTest L ∧ MyTest.isInL L s = b"
by(simp add: code_isInL_def MyTest_def can_instance_MyTest_def)
However, code export fails:
export_code code_isInL in Scala file -
No code equations for MyTest.isInL
Why do I want to do such a thing?
I'm working with a locale
in the context of a valid_graph
similar to e.g. here but finite. Testing that a graph is valid is easy. Now I want to export the code of my graph algorithms into Scala. Of course, the code should run on arbitrary valid graphs.
I'm thinking of the Scala analogy similar to something like this:
class MyTest(L: List[String]) {
require(L.distinct)
def isInL(s: String): Bool = L contains s
}
回答1:
One way to solve this is datatype refinement using invariants (see isabelle doc codegen
section 3.3). Thereby the validity assumption (distinct L
, in your case) can be moved into a new type. Consider the following example:
typedef 'a dlist = "{xs::'a list. distinct xs}"
morphisms undlist dlist
proof
show "[] ∈ ?dlist" by auto
qed
This defines a new type whose elements are all lists with distinct elements. We have to explicitly set up this new type for the code generator.
lemma [code abstype]: "dlist (undlist d) = d"
by (fact undlist_inverse)
Then, in the locale we have the assumption "for free" (since every element of the new type guarantees it; however, at some point we have to lift a basic set of operations from lists with distinct element to 'a dlist
s).
locale MyTest =
fixes L :: "string dlist"
begin
definition isInL :: "string => bool" where
"isInL s = (s ∈ set (undlist L))"
end
At this point, we are able to give (unconditional) equations to the code generator.
lemma [code]: "MyTest.isInL L s ⟷ s ∈ set (undlist L)"
by (fact MyTest.isInL_def)
export_code MyTest.isInL in Haskell file -
回答2:
I found a method, thanks to chris' tips.
Define a function to test the prerequisites/assumptions to instantiate a MyTest
definition "can_instance_MyTest L = distinct L"
The command term MyTest
reveals that MyTest
is of type string list => bool
,
this means that MyTest
is a predicate that takes a parameter and tests if this parameter fulfills MyTest
's assumptions.
We introduce a code equation ([code]
) that replaces MyTest
with the executable instance tester.
The code generator can now produce code for occurrences of e.g., MyTest [a,b,c]
lemma [code]: "MyTest = can_instance_MyTest"
by(simp add:fun_eq_iff MyTest_def can_instance_MyTest_def)
export_code MyTest in Scala file -
We yield (I replaced List[Char]
with String
for readability):
def can_instance_MyTest[A : HOL.equal](l: List[A]): Boolean =
Lista.distinct[A](l)
def myTest: (List[String]) => Boolean =
(a: List[String]) => can_instance_MyTest[String](a)
More readable pseudo-code:
def myTest(l: List[String]): Boolean = l.isDistinct
Now we need executable code for isInL
. We utilize the predefined constant undefined
. This code throws an exception if L
is not distinct.
definition code_isInL :: "string list ⇒ string ⇒ bool" where
"code_isInL L s = (if can_instance_MyTest L then s ∈ set L else undefined)"
export_code code_isInL in Scala file -
We yield:
def code_isInL(l: List[String], s:String): Boolean =
(if (can_instance_MyTest[String](l)) Lista.member[String](l, s)
else sys.error("undefined"))*)
We just need to show that the code_isInL
is correct:
lemma "b ≠ undefined ⟹ code_isInL L s = b ⟷ MyTest L ∧ MyTest.isInL L s = b"
by(simp add: code_isInL_def MyTest_def can_instance_MyTest_def MyTest.isInL_def)
(* Unfortunately, the other direction does not hold. The price of undefined. *)
lemma "¬ MyTest L ⟹ code_isInL L s = undefined"
by(simp add: code_isInL_def can_instance_MyTest_def MyTest_def)
来源:https://stackoverflow.com/questions/15316313/generating-code-from-locales-without-interpretation