Search code examples
listprologwildcardmatchingdcg

Unifying lists of different length by concatenating atoms


Consider the following list:

[my,name,is,jack,baur]

I want to unify this to the following pattern:

[my,name,is,Name]

So that the variable Name has the value 'jack baur' in the end. The variable is working as some sort of wildcard here and should unify with an unknown number of atoms/list members.

Important:

  • the variable/wildcard is not always at the end
  • there could be multiple variables/wildcards

Currently I have something like this:

rule([my,name,is,Name],[hello,Name]).

% Sentence is a list (e.g. [my,name,is,jack,baur]
answer(Sentence,Response) :-
    rule(Sentence,ResponseList),
    atomic_list_concat(ResponseList,' ',Response).

Obviously this only works when Name is exactly one word, not two.

How would I approach this problem in Prolog?


Solution

  • here a DCG possibility. It's fairly clean, I think.

    list(L) --> {length(L, _)}, L.
    
    rule(R) -->
        [my, name, is], list(Name),
        [and, i, live, in], list(Country),
        {flatten([hello, Name, of, Country],R)}.
    
    rule([hello|Name]) -->
        [my, name, is], list(Name) .
    
    answer(Sentence, Response) :-
        phrase(rule(Response), Sentence), !.
    

    with that

    ?- answer([my, name, is, bill, the, kid, and, i, live, in, new, york],R).
    R = [hello, bill, the, kid, of, new, york].
    

    the essential production here is list//1, that matches any definite length list of tokens.

    Beware: list(A),list(B),, with both A, B unbound should be avoided. It's ok instead if there are tokens in between, like in list(A),[and],list(B),