如何在 Prolog 中创建与另一个相反的 DCG 规则?
How do I create a DCG rule inverse to another in Prolog?
我正在用 Prolog 编写一个 Commodore BASIC 解释器,我正在编写一些 DCG 来解析它。我已经验证下面的 DCG 可以工作,variable
除外。我的目标是:对于任何不是布尔值、整数、浮点数或字符串的东西,它都是一个变量。但是,我通过 phrase
提供的任何内容都会导致 no
.
bool --> [true].
bool --> [false].
integer --> [1]. % how to match nums?
float --> [0.1].
string --> [Str], {atom_chars(Str, ['"' | Chars]), last(Chars, '"')}.
literal --> bool; integer; float; string.
variable --> \+ literal.
我 运行 这样的堆栈跟踪(gprolog
)
main :- trace, phrase(variable, [bar]).
看着这个,我无法弄清楚为什么 variable
失败了,因为它在 literal
中的每个案例都失败了。我猜这个错误很简单,但我仍然很困惑,所以任何擅长 Prolog 的人都知道我做错了什么吗?
| ?- main.
The debugger will first creep -- showing everything (trace)
1 1 Call: phrase(variable,[bar]) ?
2 2 Call: variable([bar],_321) ?
3 3 Call: \+literal([bar],_348) ?
4 4 Call: literal([bar],_348) ?
5 5 Call: bool([bar],_348) ?
5 5 Fail: bool([bar],_348) ?
5 5 Call: integer([bar],_348) ?
5 5 Fail: integer([bar],_348) ?
5 5 Call: float([bar],_348) ?
5 5 Fail: float([bar],_348) ?
5 5 Call: string([bar],_348) ?
6 6 Call: atom_chars(bar,['"'|_418]) ?
6 6 Fail: atom_chars(bar,['"'|_418]) ?
5 5 Fail: string([bar],_348) ?
4 4 Fail: literal([bar],_348) ?
3 3 Exit: \+literal([bar],_348) ?
2 2 Exit: variable([bar],[bar]) ?
1 1 Fail: phrase(variable,[bar]) ?
(2 ms) no
{trace}
您可以像这样检测一串整数(我添加了一个参数来收集数字):
integer([H|T]) --> digit(H), integer(T).
integer([]) --> [].
digit(0) --> "0".
digit(1) --> "1".
...
digit(9) --> "9".
至于 variable
-- 它需要使用文本,因此您需要类似于上面的 integer
的内容,但将 digit(H)
更改为可以识别字符的内容一个“变量”。
如果您需要更多线索(尽管有时会使用稍微高级的技巧):https://www.swi-prolog.org/pldoc/man?section=basics and the code is here: https://github.com/SWI-Prolog/swipl-devel/blob/master/library/dcg/basics.pl
扩展一下另一个答案,关键问题是像 \+ literal
这样的 DCG 规则不会消耗输入中的项目。它仅 检查 下一项(如果有)不是 literal
。
要实际消费一个项目,您需要使用列表目标,类似于您使用目标 [1]
消费 1
元素的方式。所以:
variable -->
\+ literal, % if there is a next element, it's not a literal
[_Variable]. % consume this next element, which is a variable
例如:
?- phrase(variable, [bar]).
true.
?- phrase((integer, variable, float), [I, bar, F]).
I = 1,
F = 0.1.
拥有那个单例变量 _Variable
有点奇怪——当您像这样解析时,您会丢失变量的名称。当您的解析器稍微扩展时,您将希望使用 DCG 规则的参数来传达规则之外的信息:
variable(Variable) -->
\+ literal,
[Variable].
例如:
?- phrase((integer, variable(Var1), float, variable(Var2)), [I, bar, F, foo]).
Var1 = bar,
Var2 = foo,
I = 1,
F = 0.1.
我正在用 Prolog 编写一个 Commodore BASIC 解释器,我正在编写一些 DCG 来解析它。我已经验证下面的 DCG 可以工作,variable
除外。我的目标是:对于任何不是布尔值、整数、浮点数或字符串的东西,它都是一个变量。但是,我通过 phrase
提供的任何内容都会导致 no
.
bool --> [true].
bool --> [false].
integer --> [1]. % how to match nums?
float --> [0.1].
string --> [Str], {atom_chars(Str, ['"' | Chars]), last(Chars, '"')}.
literal --> bool; integer; float; string.
variable --> \+ literal.
我 运行 这样的堆栈跟踪(gprolog
)
main :- trace, phrase(variable, [bar]).
看着这个,我无法弄清楚为什么 variable
失败了,因为它在 literal
中的每个案例都失败了。我猜这个错误很简单,但我仍然很困惑,所以任何擅长 Prolog 的人都知道我做错了什么吗?
| ?- main.
The debugger will first creep -- showing everything (trace)
1 1 Call: phrase(variable,[bar]) ?
2 2 Call: variable([bar],_321) ?
3 3 Call: \+literal([bar],_348) ?
4 4 Call: literal([bar],_348) ?
5 5 Call: bool([bar],_348) ?
5 5 Fail: bool([bar],_348) ?
5 5 Call: integer([bar],_348) ?
5 5 Fail: integer([bar],_348) ?
5 5 Call: float([bar],_348) ?
5 5 Fail: float([bar],_348) ?
5 5 Call: string([bar],_348) ?
6 6 Call: atom_chars(bar,['"'|_418]) ?
6 6 Fail: atom_chars(bar,['"'|_418]) ?
5 5 Fail: string([bar],_348) ?
4 4 Fail: literal([bar],_348) ?
3 3 Exit: \+literal([bar],_348) ?
2 2 Exit: variable([bar],[bar]) ?
1 1 Fail: phrase(variable,[bar]) ?
(2 ms) no
{trace}
您可以像这样检测一串整数(我添加了一个参数来收集数字):
integer([H|T]) --> digit(H), integer(T).
integer([]) --> [].
digit(0) --> "0".
digit(1) --> "1".
...
digit(9) --> "9".
至于 variable
-- 它需要使用文本,因此您需要类似于上面的 integer
的内容,但将 digit(H)
更改为可以识别字符的内容一个“变量”。
如果您需要更多线索(尽管有时会使用稍微高级的技巧):https://www.swi-prolog.org/pldoc/man?section=basics and the code is here: https://github.com/SWI-Prolog/swipl-devel/blob/master/library/dcg/basics.pl
扩展一下另一个答案,关键问题是像 \+ literal
这样的 DCG 规则不会消耗输入中的项目。它仅 检查 下一项(如果有)不是 literal
。
要实际消费一个项目,您需要使用列表目标,类似于您使用目标 [1]
消费 1
元素的方式。所以:
variable -->
\+ literal, % if there is a next element, it's not a literal
[_Variable]. % consume this next element, which is a variable
例如:
?- phrase(variable, [bar]).
true.
?- phrase((integer, variable, float), [I, bar, F]).
I = 1,
F = 0.1.
拥有那个单例变量 _Variable
有点奇怪——当您像这样解析时,您会丢失变量的名称。当您的解析器稍微扩展时,您将希望使用 DCG 规则的参数来传达规则之外的信息:
variable(Variable) -->
\+ literal,
[Variable].
例如:
?- phrase((integer, variable(Var1), float, variable(Var2)), [I, bar, F, foo]).
Var1 = bar,
Var2 = foo,
I = 1,
F = 0.1.