DCG库函数的Prolog类型错误

时间:2016-05-22 23:23:39

标签: prolog dcg

我正在尝试为命令界面编写DCG。我们的想法是读取一串输入,将其拆分为空格,然后将生成的标记列表交给DCG,将其解析为命令和参数。解析的结果应该是一个术语列表,我可以使用=..构建一个目标来调用。但是,我对SWI-Prolog(版本7.2.3)中的字符串类型情况感到非常困惑。 SWI-Prolog包含一个basic DCG functionality库,包括一个应该解析整数的目标integer//1。它由于类型错误而失败,但更大的问题是我无法弄清楚如何使用“令牌列表”在SWI-Prolog中很好地使DCG工作。

这是我正在尝试做的事情:

:- use_module(library(dcg/basics)).

% integer//1 is from the dcg/basics lib
amount(X) --> integer(X), { X > 0 }.
cmd([show,all]) --> ["show"],["all"].
cmd([show,false]) --> ["show"].
cmd([skip,X]) --> ["skip"], amount(X).

% now in the interpreter:
?- phrase(cmd(L), ["show","all"]).
L = [show, all].
% what is the problem with this next query?
?- phrase(cmd(L), ["skip", "50"]).
ERROR: code_type/2: Type error: `character' expected, found `"50"' (a string)

我已阅读SWI手册的Section 5.2,但它并未完全回答我的问题:

  1. integer//1库中dcg/basics的预期类型是什么?错误消息显示“字符”,但我找不到任何有用的参考,这究竟是什么意思以及如何为它提供“正确”的输入。
  2. 如何将字符串(标记)列表传递给phrase/2,以便我可以使用integer//1将标记解析为整数?
  3. 如果无法使用integer//1原语将一串数字解析为整数,我该如何实现?
  4. 我在SWI-Prolog中使用double_quote标志的不同值以及使用单个字符串作为输入的不同输入格式(例如使用原子列表)进行了相当多的实验,即{ {1}}而不是"skip 50",等等,但我觉得有关DCG如何工作的假设,我不明白。

    我也研究了这三个页面,其中有很多例子,但没有一个完全解决我的问题(由于我没有足够的声誉来发布所有这些,所以省略了一些链接):

    1. Anne Ogborn的“使用SWI-Prolog中的明确条款文法”教程
    2. Amzi的教程!关于将命令接口编写为DCG的Prolog。
    3. J. R. Fisher's Prolog教程的第7.3节
    4. 第三个更广泛的问题是,如果预期整数但不能解析为一个整数,如何生成错误消息,如下所示:

      ["skip", "50"]

      一种方法是将上面的DCG中的变量% the user types: > skip 50x I didn't understand that number. 设置为某种错误值,然后稍后检查(就像假定的X目标应该由命令),但也许有更好/更惯用的方式?我编写解析器的大部分经验都来自于使用Haskell的Parsec和Attoparsec库,这些库是相当具体的声明,但工作方式有所不同,特别是在错误处理方面。

1 个答案:

答案 0 :(得分:0)

Prolog没有字符串。双引号字符序列的传统表示是代码列表(整数)。对于efficiency reasons,SWI-Prolog ver。 > = 7引入了字符串作为新的原子数据类型:

?- atomic("a string").
true.

和反引号文字现在具有以前由字符串保存的角色:

?- X=`123`.
X = [49, 50, 51].

毋庸置疑,这导致some confusion,同时也给出了Prolog的弱类型性质......

无论如何,DCG仍然可以处理(差异)字符代码列表,只需将转换器扩展为接受字符串作为终端。你的代码可能是

cmd([show,all]) --> whites,"show",whites,"all",blanks_to_nl.
cmd([show,false]) --> whites,"show",blanks_to_nl.
cmd([skip,X]) --> whites,"skip",whites,amount(X),blanks_to_nl.

可以像

一样调用
?- phrase(cmd(C), ` skip 2300 `).
C = [skip, 2300].

修改

  

如果需要整数,如何生成错误消息

我会尝试:

...
cmd([skip,X]) --> whites,"skip",whites,amount(X).

% integer//1 is from the dcg/basics lib
amount(X) --> integer(X), { X > 0 }, blanks_to_nl, !.
amount(unknown) --> string(S), eos, {print_message(error, invalid_int_arg(S))}.

prolog:message(invalid_int_arg(_)) --> ['I didn\'t understand that number.'].

试验:

?- phrase(cmd(C), ` skip 2300x `).
ERROR: I didn't understand that number.
C = [skip, unknown] ;
false.