DCG for file output

2019-07-28 21:21发布

问题:

If I have a program like this and I want the last item for a person not to have a comma following it, how do I do this? Is it best to use a DCG? How would that work?

male(bob).
male(dave).
male(fred).
male(dereck).


likes(bob,cake).
likes(bob, pie).
likes(bob, apple).

likes(dave, fish).
likes(dave, meat).
likes(dave, potato).
likes(dave, pear).

likes(fred, water).
likes(fred, beer).

likes(dereck, wine).
likes(dereck, cake).



print:-
    forall(
        male(Person),
        (
          format("~w, ",[Person]),
          forall(
             likes(Person,Item),
             format("~w, ",[Item])
          ),
          format("~n~n",[])
        )
    ).

The out put is:

 bob, cake, pie, apple, 

 dave, fish, meat, potato, pear, 

 fred, water, beer, 

 dereck, wine, cake, %<I dont want these last commas 

回答1:

Consider first a pure solution, using DCGs to translate a list of things a person likes to a list of formatting instructions that can later be interpreted:

person_likes(Who, Whats) -->
    atom(Who), atom(': '),
    likes_(Whats).

likes_([])         --> [newline].
likes_([X])        --> atom(X), [newline].
likes_([X,Y|Rest]) --> atom(X), atom(', '), likes_([Y|Rest]).

atom(A) --> [atom(A)].

As you see, the key idea is to distinguish the cases depending on the number of elements in the list. This shows you how to solve such problems very generally.

You can already use it like this:

?- phrase(person_likes(bob, [cake,pie]), Instrs).
Instrs = [atom(bob), atom(': '), atom(cake), atom(', '), atom(pie), newline].

For the desired output, you simply interpret these formatting instructions. For example:

output(newline) :- nl.
output(atom(A)) :- format("~w", [A]).

Sample query, with your example facts:

?- male(M), findall(W, likes(M,W), Whats),
   phrase(person_likes(M,Whats), Ts),
   maplist(output, Ts), false.

Yielding:

bob: cake, pie, apple
dave: fish, meat, potato, pear
fred: water, beer
dereck: wine, cake

Of course, you can use the same pattern to obtain a shorter, impure version (using side-effects) in this concrete case. But you then cannot use it in the other direction! So, it is worthwhile to study the pure version.