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:With
typedef
之前测试了区分性,引入了一个新类型,比如说
n
,它是从现有类型中“分割出来的”,比如说
t
。然后,对于类型为
n
的每个元素
x
,都有一个类型为
t
的代表,它是通过
Rep\u nx
获得的。另一个方向,即从类型为
t
的给定元素
x
获取类型为
n
的抽象值,由(未指定的)函数
Abs\u n
覆盖,该函数仅定义在分割集的成员上。这些是默认名称。
morphisms
注释只允许更改这两个函数的名称。@corny:关于您关于“检查生成的代码,我可以自由创建一个
dlist
,它不明显…”的评论。是的,你可以。但是,只要整个代码是由Isabelle生成的(并且不是手工修改的),您就可以保证不会发生这种情况。当然,如果您想/必须将生成的代码与手动编写的代码混合使用,这是一个问题。。。也许可以让生成的代码在目标语言中将这些类型转换为抽象类型,我还没有研究它。