与输入的其余部分匹配的DCG

时间:2014-09-10 04:36:47

标签: prolog dcg

这是谓词应该做的事情,即收集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)
    }.

3 个答案:

答案 0 :(得分:2)

回答我自己的愚蠢问题:

@CapelliC提供了一个有效的解决方案(+1)。它做了一些我不明白的事情:-(但真正的问题是我不理解我试图解决的问题。真正的问题是:

问题

您需要解析一个代码列表作为输入。结果应该是一个术语。你知道这个代码列表的开头非常接近其余的代码。换句话说,它以"关键字"开头。定义内容。在某些情况下,在输入中的某个点之后,不需要解析其余内容:相反,它们在结果项中被收集为代码列表。

解决方案

一种可能的解决方案是在两次调用phrase/3时解析解析(因为没有理由不这样做?):

  1. 阅读关键字(首次调用phrase/3)并将其设为原子;
  2. 在表格中查看其余部分应该是什么样的;
  3. 仅解析需要解析的内容(第二次调用phrase/3)。
  4. 代码

    所以,使用(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]