Scala 从区域设置生成代码而不进行解释
我希望直接从Scala 从区域设置生成代码而不进行解释,scala,code-generation,isabelle,Scala,Code Generation,Isabelle,我希望直接从locale定义生成代码,而不进行解释。例如: (* 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 ∈
locale
定义生成代码,而不进行解释。例如:
(* 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
实例化MyTest
的假设是可执行的,我可以为它们生成代码
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 -
我可以定义一个函数来执行任意MyTest
的isInL
定义
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)
但是,代码导出失败:
export_code code_isInL in Scala file -
No code equations for MyTest.isInL
我为什么要做这样的事?
我在有效图
的上下文中使用区域设置
,类似于但有限。测试图形是否有效很容易。现在我想把我的图形算法的代码导出到Scala中。当然,代码应该在任意有效图上运行
我想到了类似于这样的Scala类比:
class MyTest(L: List[String]) {
require(L.distinct)
def isInL(s: String): Bool = L contains s
}
解决这个问题的一种方法是使用不变量对数据类型进行细化(请参见
isabelle doc codegen
第3.3节)。因此,有效性假设(distinct L
,在您的情况下)可以移动到一个新类型中。考虑下面的例子:
typedef 'a dlist = "{xs::'a list. distinct xs}"
morphisms undlist dlist
proof
show "[] ∈ ?dlist" by auto
qed
这定义了一个新类型,其元素都是具有不同元素的列表。我们必须为代码生成器显式设置这种新类型
lemma [code abstype]: "dlist (undlist d) = d"
by (fact undlist_inverse)
lemma [code]: "MyTest.isInL L s ⟷ s ∈ set (undlist L)"
by (fact MyTest.isInL_def)
export_code MyTest.isInL in Haskell file -
然后,在区域设置中,我们有“免费”的假设(因为新类型的每个元素都保证了这一点;但是,在某些时候,我们必须将一组基本操作从具有不同元素的列表提升到数据列表中)
在这一点上,我们能够给代码生成器提供(无条件)方程
lemma [code abstype]: "dlist (undlist d) = d"
by (fact undlist_inverse)
lemma [code]: "MyTest.isInL L s ⟷ s ∈ set (undlist L)"
by (fact MyTest.isInL_def)
export_code MyTest.isInL in Haskell file -
多亏了克里斯的提示,我找到了一个方法 定义一个函数来测试先决条件/假设,以实例化
MyTest
definition "can_instance_MyTest L = distinct L"
命令term MyTest
显示MyTest
的类型为string list=>bool
,
这意味着MyTest
是一个谓词,它接受一个参数并测试该参数是否满足MyTest
的假设。
我们引入了一个代码等式([code]
),它用可执行实例测试仪取代了MyTest
。
代码生成器现在可以为出现的代码生成代码,例如,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 -
我们产生(为了可读性,我用字符串替换了列表[Char]
):
更可读的伪代码:
def myTest(l: List[String]): Boolean = l.isDistinct
现在我们需要isInL
的可执行代码。我们使用预定义的常量未定义的。如果L
不明确,此代码将引发异常
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 -
我们得出:
def code_isInL(l: List[String], s:String): Boolean =
(if (can_instance_MyTest[String](l)) Lista.member[String](l, s)
else sys.error("undefined"))*)
我们只需要证明code\u isInL
是正确的:
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)
使用2013年2月12日的codegen doc版本,§3.3不是很容易理解(并且从第一句中的键入开始…)morphisms undlist dlist
做什么?检查生成的代码,我可以自由创建一个不明显的dlist
,并将其传递给isInL
。如何防止这种情况?在我最初的示例中,代码在执行isInL
@corny:Withtypedef
之前测试了区分性,引入了一个新类型,比如说n
,它是从现有类型中“分割出来的”,比如说t
。然后,对于类型为n
的每个元素x
,都有一个类型为t
的代表,它是通过Rep\u nx
获得的。另一个方向,即从类型为t
的给定元素x
获取类型为n
的抽象值,由(未指定的)函数Abs\u n
覆盖,该函数仅定义在分割集的成员上。这些是默认名称。morphisms
注释只允许更改这两个函数的名称。@corny:关于您关于“检查生成的代码,我可以自由创建一个dlist
,它不明显…”的评论。是的,你可以。但是,只要整个代码是由Isabelle生成的(并且不是手工修改的),您就可以保证不会发生这种情况。当然,如果您想/必须将生成的代码与手动编写的代码混合使用,这是一个问题。。。也许可以让生成的代码在目标语言中将这些类型转换为抽象类型,我还没有研究它。