我将首先为您提供三个如何使语法起作用的替代方法。然后我将解释其余的谜团:为什么cc
使用您的初始方法,但解析/线性化不起作用,以及如何cc
从 Python 中实际使用(只是不使用 PGF 库)。
1.修正你的语法
(a) 大型词典,应用语法作为 RGL 之上的一层
在您的示例中,您正在打开DictEng
,因此我假设您希望您的应用程序具有大型词典。
如果您希望能够使用大型词典进行解析,则它需要成为语法抽象语法的一部分。第一个错误是您将DictEng 作为资源打开,而不是扩展。(请参阅 教程以刷新您的记忆。)
因此,如果您希望您的抽象语法包含一个名为 的词典条目dog_N
,您可以将其作为函数的参数提供MySentence
,您将需要按如下方式修改您的语法。
抽象的:
abstract Test = Cat, DictEngAbs ** {
flags startcat = NP ;
fun
MySentence : N -> NP ;
}
具体的:
concrete TestEng of Test = CatEng, DictEng ** open SyntaxEng in {
lin
MySentence noun = mkNP aSg_Det noun ;
}
在这个解决方案中,我保持dog_N
必须正确的约束,并更改其他所有内容。所以变化是:
- 移除了你的猫(
Noun
和Sentence
)——取而代之的是,从 RGL 抽象语法继承 Cat 模块。
- 该类型的
MySentence
作品现在在 RGL 猫N
和NP
. 在您最初的方法中,这些是您的定制猫的 lincats。
所以这个语法是RGL片段的扩展。特别是,我们重用了 RGL 类型和词典,但没有重用句法函数。
(实际上,我们也在使用 RGL 语法函数,但通过 API,而不是通过扩展 RGL 抽象语法!mkNP
操作来自 RGL API,我们在范围内,因为我们在具体语法中打开了 SyntaxEng。)
(b) 小词库,纯应用语法,RGL只是一种资源
在这里,我决定保留您的定制猫和它们的 lincats。这意味着我需要明确添加词典。像这样:
abstract Test = {
flags startcat = Sentence ;
cat
Sentence; Noun;
fun
MySentence : Noun -> Sentence;
-- Lexicon needs to be given explicitly
dog_N : Noun ;
cat_N : Noun ;
}
如果我不扩展 DictEngAbs,就像在前面的方法中那样,并且我想在范围内拥有一些名为 的东西dog_N
,我必须自己创建它。为了能够解析或线性化任何东西,它必须是抽象语法。
所以具体来说,我们再次打开 DictEng,并使用它来线性化这个抽象语法的词项。
concrete TestEng of Test = open SyntaxEng, DictEng in {
lincat
Sentence = NP;
Noun = N;
lin
MySentence noun = mkNP aSg_Det noun ;
-- Lexicon can use the definitions from DictEng
dog_N = DictEng.dog_N ;
cat_N = DictEng.cat_N ;
}
当然,如果你想要一个大词典,这不是那么有用。但是,如果您实际上并不关心大型词典,那么这会导致最简单和最小的语法。RGL 仅用作资源,严格通过 API。正如我们所看到的,这个语法只是打开了 SyntaxEng 和 DictEng,它所有的猫和乐趣都在摘要中定义。没有什么隐藏的,没有什么令人惊讶的,没有体积。此外,没有覆盖,这个语法可以从字面上说“一只狗”和“一只猫”。
(c) 大型词典,扩展 RGL,但也保留您的自定义猫
这实际上与解决方案 (a) 相同,但我只是展示了如何扩展 RGL 片段并保留您的自定义猫,如果您想这样做的话。
这是抽象语法。
abstract Test = Cat, DictEngAbs ** {
flags startcat = Sentence ;
cat
Sentence; Noun;
fun
MySentence : Noun -> Sentence;
-- applied to lexical items from the dictionary
n2noun : N -> Noun ;
}
我们从扩展 Cat 和 DictEngAbs 重新开始。但我们也定义了我们自己的猫。它起作用的原因是我们的强制功能,n2noun : N -> Noun
.
- 我们同时拥有 RGL 猫和我们的定制猫
- 我们的词典都在 RGL 猫中 (DictEngAbs)
- 我们的自定义句法函数适用于我们的自定义猫
- 因此,我们需要从
N
in DictEngAbs 转换为Noun
. 因为 MySentence 只接受名词。
n2noun
转换对我们来说也是如此。这是具体的语法:
concrete TestEng of Test = CatEng, DictEng ** open SyntaxEng in {
lincat
Sentence = NP;
Noun = N;
lin
MySentence noun = mkNP aSg_Det noun ;
n2noun n = n ;
}
语法树现在看起来像这样:
Test> gr -number=3 | l -treebank
Test: MySentence (n2noun hairstylist_N)
TestEng: a hairstylist
Test: MySentence (n2noun nomia_N)
TestEng: a nomia
Test: MySentence (n2noun seminar_N)
TestEng: a seminar
如果您更喜欢更短的语法树MySentence hairstylist_N
,那么请选择解决方案 (a)。
对于这样一个小例子,我想不出与 (a) 相比的具体好处,但在更大的系统中,它对于添加限制很有用。例如,假设您Noun
从另一个来源添加了更多 s,并且不想将它们作为参数提供给其他函数,但 RGLN
可以作为所有函数的参数,那么将 cat 与强制函数分开是很有用的。
2. 剩下的问题
我已经在我的三个替代解决方案中谈到了一些事情,但仍有一些问题我没有解释。这是其余的奥秘。
为什么您的第一种方法在 GF shell 中有效,但在 Python 中无效?
因为您没有尝试解析和线性化,而是使用cc
(compute concrete) with -retain
flag。当您在 GF shell 中打开语法时-retain
,它会将所有本地临时帮助程序的内容保留在范围内——这包括您打开的模块。因此dog_N
fromDictEng
在范围内,但仅适用于 cc 在 GF shell 中。
您是否尝试在 GF shell 中解析和线性化?如果您尝试,您将在那里遇到失败:
Test> l MySentence dog_N
Function dog_N is not in scope
与 相比cc
,解析和线性化不能依赖于局部定义。它必须在抽象语法中,否则它不存在。如果您想使用 PGF 库从 Python 访问语法,则必须将语法编译成 PGF 格式。而且 PGF 格式不保留本地定义。
实际使用cc
Python
从技术上讲,您可以使用 Python 中的 cc,但不能使用 PGF 库。如果您将 GF shell 作为子进程打开,并将未编译的 GF 文件作为输入,它会起作用。这行得通,我把它放在一个名为test.py
:
from subprocess import Popen, PIPE
gfscript = ['i -retain TestEng.gf',
'cc -one MySentence dog_N']
command = 'gf -run'.split()
gfinput = '\n'.join(gfscript)
gf = Popen(command, stdin=PIPE, stdout=PIPE)
stdout, _stderr = gf.communicate(gfinput.encode('utf-8'))
stdout = stdout.decode('utf-8')
print(stdout)
并在命令行上运行它,在同一目录中使用您的原始语法,给我想要的答案。
python3 test.py
a dog
记住,你不能cc
用 GF shell 解析任何东西,也不能从 Python 子进程解析任何东西。它只是用于生成输出。
编译为 PGF
最后的小问题:--output-format=haskell
如果您不需要抽象语法的 Haskell 版本,则不需要标志。就gf -make TestEng.gf
足以产生 PGF。