1

我有这两个文件在 GF shell 中运行得非常好

我的GF代码

测试.gf

abstract Test = {
    cat
        Sentence; Noun;
    fun
        MySentence : Noun -> Sentence;
}

测试工程.gf

concrete TestEng of Test = open SyntaxEng, ParadigmsEng, DictEng in {
    lincat
        Sentence = NP;
        Noun = N;
    lin
        MySentence noun = mkNP (aSg_Det) (noun);
}

我在 GF shell 中运行它们的方式如下:

> i -retain TestEng.gf
> cc -one MySentence dog_N
a dog

这给出了预期的结果。

我的 PGF 代码

然后我使用 Linux 命令将该文件转换为 `.pgf' 格式

> gf -make --output-format=haskell TestEng.gf
linking ... OK
Writing Test.pgf...
Writing Test.hs...

输出这两个文件Test.hsTest.pgf

问题

我的 Python 代码

测试.py

import pgf


gr = pgf.readPGF("Test.pgf")
e = pgf.readExpr("MySentence dog_N")

print(gr.languages.keys())          #To check all languages
eng = gr.languages["TestEng"]
print(eng.linearize(e))

当我运行上面的代码时,我得到以下输出:

> python3 test.py
dict_keys(['TestEng'])
a [dog_N]

为什么python输出a [dog_N]而不是a dog

4

1 回答 1

1

我将首先为您提供三个如何使语法起作用的替代方法。然后我将解释其余的谜团:为什么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必须正确的约束,并更改其他所有内容。所以变化是:

  • 移除了你的猫(NounSentence)——取而代之的是,从 RGL 抽象语法继承 Cat 模块。
  • 该类型的MySentence作品现在在 RGL 猫NNP. 在您最初的方法中,这些是您的定制猫的 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)
  • 我们的自定义句法函数适用于我们的自定义猫
  • 因此,我们需要从Nin 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 -retainflag。当您在 GF shell 中打开语法时-retain,它会将所有本地临时帮助程序的内容保留在范围内——这包括您打开的模块。因此dog_NfromDictEng在范围内,但仅适用于 cc 在 GF shell 中。

您是否尝试在 GF shell 中解析和线性化?如果您尝试,您将在那里遇到失败:

Test> l MySentence dog_N
Function dog_N is not in scope

与 相比cc,解析和线性化不能依赖于局部定义。它必须在抽象语法中,否则它不存在。如果您想使用 PGF 库从 Python 访问语法,则必须将语法编译成 PGF 格式。而且 PGF 格式不保留本地定义。

实际使用ccPython

从技术上讲,您可以使用 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。

于 2022-01-05T06:21:36.933 回答