这是谓词应该做的事情,即收集DCG的一部分时输入的内容:
rest([H|T], [H|T], []).
rest([], [], []).
但是我很难将其定义为DCG ......或者它是否可行?
这当然不一样(虽然在以相同方式使用时也是如此):
rest([H|T]) --> [H], !, rest(T).
rest([]) --> [].
我认为我需要这个的原因是rest//1
是我需要解析输入的一组DCG规则的一部分。我可以phrase(foo(T), Input, Rest)
,但是我必须再拨打phrase(bar(T1), Rest)
。
说我知道我输入的所有内容都是一个数字字符串,我想要一个整数:
phrase(stuff_n(Stuff, N), `some other stuff, 1324`).
stuff_n(Stuff, N) -->
stuff(Stuff),
rest(Rest),
{ number_codes(N, Rest),
integer(N)
}.
答案 0 :(得分:2)
回答我自己的愚蠢问题:
@CapelliC提供了一个有效的解决方案(+1)。它做了一些我不明白的事情:-(但真正的问题是我不理解我试图解决的问题。真正的问题是:
您需要解析一个代码列表作为输入。结果应该是一个术语。你知道这个代码列表的开头非常接近其余的代码。换句话说,它以"关键字"开头。定义内容。在某些情况下,在输入中的某个点之后,不需要解析其余内容:相反,它们在结果项中被收集为代码列表。
一种可能的解决方案是在两次调用phrase/3
时解析解析(因为没有理由不这样做?):
phrase/3
)并将其设为原子; phrase/3
)。所以,使用(O' Keefe 1990)的方法并利用SWI-Prolog中提供的library(dcg/basics)
和文件rest.pl
:
:- use_module(library(dcg/basics)).
codes_term(Codes, Term) :-
phrase(dcg_basics:nonblanks(Word), Codes, Codes_rest),
atom_codes(Keyword, Word),
kw(Keyword, Content, Rest, Term),
phrase(items(Content), Codes_rest, Rest).
kw(foo, [space, integer(N), space, integer(M)], [], foo(N, M)).
kw(bar, [], Text, bar(Text)).
kw(baz, [space, integer(N), space], Rest, baz(N, Rest)).
items([I|Is]) -->
item(I),
items(Is).
items([]) --> [].
item(space) --> " ".
item(integer(N)) --> dcg_basics:integer(N).
重要的是,"休息"根本不需要由DCG规则处理。
这个解决方案很好,因为它是确定性的,并且很容易扩展:只需在kw/4
表和item//1
规则中添加子句。 (注意在启动SWI-Prolog时使用--traditional
标志,用于双引号分隔的代码列表)
$ swipl --traditional --quiet
?- [rest].
true.
?- codes_term("foo 22 7", T).
T = foo(22, 7).
?- codes_term("bar 22 7", T).
T = bar([32, 50, 50, 32, 55]).
?- codes_term("baz 22 7", T).
T = baz(22, [55]).
答案 1 :(得分:1)
替代方案(不会留下选择点)是使用带有lambda表达式的call//1
内置非终端。使用Logtalk的lambda表达式语法来说明:
rest(Rest) --> call({Rest}/[Rest,_]>>true).
然而,这个解决方案有点讨厌,因为它使用了一个在lambda表达式中具有双重角色的变量(它使用Logtalk编译器触发警告)。用法示例:
:- object(rest).
:- public(test/2).
test(Input, Rest) :-
phrase(input(Rest), Input).
input(Rest) --> [a,b,c], rest(Rest).
rest(Rest) --> call({Rest}/[Rest,_]>>true).
% rest([C|Cs]) --> [C|Cs]. % Carlo's solution
:- end_object.
假设上述对象保存在dcg_rest.lgt
源文件中:
$ swilgt
...
?- {dcg_rest}.
* Variable A have dual role in lambda expression: {A}/[A,B]>>true
* in file /Users/pmoura/Desktop/dcg_rest.lgt between lines 13-14
* while compiling object rest
% [ /Users/pmoura/Desktop/dcg_rest.lgt loaded ]
% 1 compilation warning
true.
?- rest::test([a,b,c,d,e], Rest).
Rest = [d, e].
您应该能够使用其他lambda表达式实现(例如Ulrich的lambda
库)获得相同的结果。
答案 2 :(得分:-1)
可能是
rest([C|Cs]) --> [C|Cs] .
至少在SWI-Prolog中,似乎运行(我使用库(dcg / basics)来获取数字)
line(I,R) --> integer(I), rest(R).
?- phrase(line(N,R), `6546 okok`).
N = 6546,
R = [32, 111, 107, 111, 107]