Lambda 演算(lambda calculus)是一种简单的语言,常用于研究编程语言理论。该语言仅由变量引用、单参数函数和函数应用组成。Lambda 演算由一系列 lambda 项(lambda terms)组成。Lambda 演算的语法规定,所有合法的 lambda 项都可以通过应用以下三条规则来构建:
- 变量 $x$(一个除
lambda以外的非空字符串)本身是一个 lambda 项; - 如果 $t$ 是一个合法的 lambda 项,且 $x$ 是一个变量,那么
(lambda (x) t)是一个 lambda 项(称为 lambda 抽象,lambda abstraction),这里 $x$ 在 $t$ 中至少出现一次; - 如果 $t$ 和 $s$ 是 lambda 项,那么
(t s)是一个 lambda 项(称为应用,application)。
除此之外,没有其他东西是 lambda 项。因此,一个 lambda 项是合法的,当且仅当它可以通过重复应用这三条规则来获得。注意,第二条和第三条规则中的括号不能省略。
一个 lambda 抽象 (lambda (x) t) 是一个匿名函数的定义,该函数能够接受单个输入 $x$ 并将其代入项 $t$ 中。该抽象在项 $t$ 中绑定了变量 $x$,因此我们称其为变量 $x$ 的 lambda 绑定。
一个应用 (t s) 表示将函数 $t$ 应用于输入 $s$,即表示调用函数 $t$ 并传入参数 $s$ 以产生 $t(s)$ 的行为。
为了理解其工作原理,考虑扩展了算术运算符的 lambda 演算。在那种语言中,一个 lambda 抽象 (lambda (x) x + 5)(其中 $x$ 被绑定)定义了一个函数 $f(x) = x + 5$。而一个应用 ((lambda (x) x + 5) 3) 将函数 $f(x) = x + 5$ 应用于输入 $3$,并产生 $f(3) = 3 + 5 = 8$。
我们说一个变量在 lambda 项 $t$ 中自由出现(occurs free),如果它在 $t$ 中的某些出现不在该变量的任何 lambda 绑定内部。例如:
- $x$ 在 $x$ 中自由出现;
- $x$ 在 $y$ 中不自由出现;
- $x$ 在
(lambda (x) (x y))中不自由出现; - $x$ 在
(lambda (y) (x y))中自由出现; - $x$ 在
((lambda (x) x) (x y))中自由出现,这是一个产生(x y)的应用,其中 $x$ 自由出现; - $x$ 在
(lambda (y) (lambda (z) (x (y z))))中自由出现。
现在给你一个 lambda 项 $t$,你需要找到在 $t$ 中自由出现的所有不同的变量。
输入格式
输入的第一行包含一个正整数 $T$,表示测试用例的数量。接下来有 $T$ 行,每行包含一个非空字符串,表示一个 lambda 项。
每个 lambda 项中的变量仅包含拉丁字母和连字符(-),且长度不超过 20 个字符。
保证输入中的所有 lambda 项都是合法的,且所有 lambda 项的总长度不超过 $10^7$。
输入中可能会有一些额外的空格,只要它们不会引起歧义即可。
输出格式
对于每个测试用例,首先输出用例编号,然后在单行中输出在 lambda 项中自由出现的所有不同变量。这些变量应按字典序输出,相邻的两个变量之间应有一个空格。每个测试用例的冒号后面应该有一个空格。
样例
输入样例 1
6 x y (lambda (x) (x y)) (lambda (y) (x y)) ( (lambda (x) x) (x y) ) ( lambda (y) ( lambda (z) (x (y z)) ) )
输出样例 1
Case #1: x Case #2: y Case #3: y Case #4: x Case #5: x y Case #6: x
说明
一个项的自由变量是指那些没有被 lambda 抽象绑定的变量。一个表达式的自由变量集合可以通过归纳定义如下:
- $x$ 的自由变量仅为 $x$;
(lambda (x) t)的自由变量集合是 $t$ 的自由变量集合,但移除了 $x$;(t s)的自由变量集合是 $t$ 的自由变量集合与 $s$ 的自由变量集合的并集。
我们可以用上下文无关文法(CFG)来定义它:
LcExp ::= Variable
::= (lambda (Variable) LcExp)
::= (LcExp LcExp)其中变量(Variable)是除 lambda 以外的任何字符串。