Search code examples
prologdcg

How do I assert a DCG rule in Prolog?


The following Prolog prints done for goals test1 and test2, but not test3. My understanding is that match_test2 and match_test3 in this code should be equivalent. How do I create a DCG rule via an assertion?

setup(['t','e','s','t']).

match_test1 --> ['t','e','s','t'].
test1 :-
    setup(C),
    phrase(match_test1,C),
    write("done").

test2 :-
    setup(C),
    assert(match_test2(['t','e','s','t'],[])),
    phrase(match_test2,C),
    write("done").

test3 :-
    setup(C),
    assert(match_test3 --> ['t','e','s','t']),
    phrase(match_test3,C),
    write("done").

Using SWI-Prolog version 7.2.3 for x86_64-darwin14.3.0, running as swipl -l bug.pl -t test1 (or test2, test3)


Solution

  • Use expand_term/2 to translate the DCG to a regular clause first:

    ?- expand_term(match_test1 --> [t,e,s,t], Clause).
    Clause =  (match_test1([t, e, s, t|_1498], _1498):-true).
    

    Then use assertz/1 as usual on Clause, i.e., assertz(Clause).

    Note that you can write down the atoms directly, i.e., instead of 'e', simply write e.

    In addition, consider setting double_quotes to chars by adding the directive:

    :- set_prolog_flag(double_quotes, chars).
    

    Now you can write, very conveniently:

    ?- T = "test".
    T = [t, e, s, t].
    

    This syntax is very nice and makes DCGs a lot easier to debug and work with.