让 Alloy 中块外的声明

Let declarations outside of blocks in Alloy

我最近遇到一些 Alloy 模型,这些模型具有不属于模型中任何块的“let”语句。 Alloy 分析器可以很好地解析这些模型,所以我知道这是有效的 Alloy 语法。但是,在 https://alloytools.org/download/alloy4-grammar.txt 上发布的 Alloy v4 语法或 Daniel Jackson 在 Alloy 上的书中的语法中没有规定“let”语句可以出现在块之外。以下摘录显示了这些“let”语句的示例。

let bitXorTable = {
  i: bits,
  j: bits,
  k: bitAndTable[bitOrTable[i, j], bitNotTable[bitAndTable[i, j]]]
}

pred halfAdder(m: Int, n: Int, s: Int, c: Int) {
  s = bitXorTable[m, n]
  c = bitAndTable[m, n]
}

我正在为 Alloy 创建一个 ANTLR 解析器,我想知道是否应该将此规则添加到我的语法中。难道这些“let”语句只在Alloy的某些版本(newer/older)中有效?

我还没有看过语法,但是在 Alloy 网站的 Macros

下有介绍

Untyped macros can be defined at the top level of a file. All 3 syntax are equivalent. (If parameterless, then [ ] can be omitted.)

 let a[x,y,z]   {...}
 let a[x,y,z] = {...}
 let a[x,y,z] = .....

Macro expansion obeys proper grammar, so each argument to a macro must be an integer/boolean/set/relation or must be a (possibly partial) call to a predicate/function/macro.

Macros are untyped, so in a file we can’t have 2 macros with the same name. Also, if a macro is in scope, it always overrides other possible sig/field/fun/pred with the same name (Just like when inside a paragraph if we see let x=y | F, then in F we always take x to mean y, even if globally there is some other sig x or some other field x)

Lexical scoping: Inside a macro body, if you refer to a name not in the parameter list, then we will resolve it from the file that “defined” the macro, rather than resolve it from the file that “calls” the macro.

Currying: if you call a macro with insufficient number of arguments, then the result is a new macro with the first N parameters filled in, like currying.