make multiple assert basing on pattern matching

2019-09-09 13:17发布

问题:

Given a parse tree of a string my goal is to update my knowledge base.

From a sentence with variable length like the following:

"node 1 is near node 2 that is near node 3 that is near node 4 that..."

in my representation becomes a parse tree representation of the sentence, for example:

 s(desc(np(noun(node),id(1)),vp(verb(is),prep(near),np(noun(node),id(2),rel_clause(rel(that)...

from which I'd like to extract and assert the following informations:

 edge(1,2),edge(2,3),edge(3,4).

How can I achieve this goal?

I've tried to manage some case with something like

 :- dynamic edge/2.

   extract(T):- T= s(desc(np(noun(node),id(A)),vp(verb(is),prep(near),np(noun(node),id(B)))),
   assert(edge(A,B)).

   extract(T):- T= s(desc(np(noun(node),id(A)),vp(verb(is),prep(near),np(noun(node),id(B),rel_clause(rel(that)...

etc but I'd like to manage potential infinite sentences.

I'm using SWI-prolog.

EDIT: complete example of a parse tree I get in input:

 desc(np(noun(node), id(1)), vp(verb(is), prep(near), np(noun(node), id(2), 
     rel_clause(rel(that), vp(verb(is), prep(near), np(noun(node), id(3),  
     rel_clause(rel(that), vp(verb(is), prep(near), np(noun(node), id(4))))))))) 

回答1:

The first thing to do is come up with a more useable description of your data. One way is to break it down like this:

description = desc(subject, verb_part)
subject = np(noun(node), id(A))
verb_part = vp(verb(is), prep(near), object_part)
object_part = np(noun(node), id(B))
object_part = np(noun(node), id(B), rel_part)
rel_part = relcl(rel(that), verb_part)

From here, you can see where the recursion occurs and write predicates which align with the definitions above:

% description = desc(subject, verb_part)
% subject = np(noun(node), id(A))
%
extract(desc(np(noun(node), id(A)), VerbPart)) :-
    select_edge(A, VerbPart).

% verb_part = vp(verb(is), prep(near), object_part)
%
select_edge(A, vp(verb(is), prep(near), ObjectPart)) :-
    connect_node(A, ObjectPart).

% object_part = np(noun(node), id(B))
%
connect_node(A, np(noun(node), id(B))) :-
    assertz(edge(A, B)).

% object_part = np(noun(node), id(B), rel_part)
% rel_part = relcl(rel(that), verb_part)
%
connect_node(A, np(noun(node), id(B), relcl(rel(that), VerbPart))) :-
    assertz(edge(A, B)),
    select_edge(B, VerbPart).

To execute:

| ?- extract(desc(np(noun(node), id(1)), vp(verb(is), prep(near), np(noun(node), id(2),
     relcl(rel(that), vp(verb(is), prep(near), np(noun(node), id(3),
     relcl(rel(that), vp(verb(is), prep(near), np(noun(node), id(4))))))))))).

true ? ;

no

The results are asserted, as can be seen if we list the edge/2 facts:

| ?- listing(edge).

% file: user_input

edge(1, 2).
edge(2, 3).
edge(3, 4).

yes

You can also collect the edges in a list instead of asserting them, and have a result of the query be, [edge(1,2), edge(2,3), edge(3,4)]:

extract(desc(np(noun(node), id(A)), VerbPart), Edges) :-
    select_edge(A, VerbPart, Edges).

select_edge(A, vp(verb(is), prep(near), ObjectPart), Edges) :-
    connect_node(A, ObjectPart, Edges).

connect_node(A, np(noun(node), id(B)), [edge(A,B)]).
connect_node(A, np(noun(node), id(B), relcl(rel(that), VerbPart)), [edge(A,B)|Edges]) :-
    select_edge(B, VerbPart, Edges).

And then assert them all at once from the resulting list with maplist:

extract(Description, Edges), maplist(assertz, Edges).


标签: prolog