在序言中管理多个匹配

Manage multiple matching in prolog

假设您输入了一个图表描述,例如 "A is near B" 并且您想要更新您的知识库。

使用 Prolog 我决定使用这个解决方案:

:- dynamic edge/2.

store(Desc):- Desc=[A,is,near,B],
          assert(edge(A,B)),
          write(A-B).


store(Desc):- Desc=[A,is,near,B,that,is,near,C],
          write(A-B),nl,
          write(B-C),
          assert(edge(A,B)),
          assert(edge(B,C)).

我想将解析扩展到潜在的无限句子,例如: '1 接近 2 接近 3 接近 4 等', 所以我想做的是(用类似伪代码的符号表示的想法):

  procedure store(Sentence)
  begin
  foreach 'X is near Y' in Sentence  assert edge(X,Y).
  foreach 'X that is near Y' in Sentence assert edge(X,Y).
  end

如何在 Prolog 中实现这一点?

首先,您可以一步完成模式匹配和统一。其次,您需要使谓词递归。 使用 该句子中的第一个单词(即列表的第一个元素)并让递归目标处理其余部分:

store([A, is, near, B]):-
    assert_edge(A, B).
store([A, is, near, B, that|Other]):-
    assert_edge(A, B),
    store([B|Other]).

assert_edge(A, B):-
    ...

另一种方法是使用 setof/3 和列表的内置谓词,例如 append/3:

?- L = [a, that, is, near, b, that, is, near, c, that, is, near, d],
   setof(A-B, L1^L2^append(L1,[A, that, is, near, B|L2], L), Edges).

L = [a, that, is, near, b, that, is, near, c|...],
Edges = [a-b, b-c, c-d].

DCG 方法在这里可以很好地工作:

store --> [A], is_near(B), { assertz(edge(A, B)) }, and_near(B).

and_near(_) --> [].
and_near(A) --> [that], is_near(B), { assertz(edge(A, B)) }, and_near(B).

is_near(A) --> [is, near, A].

store(L) :- phrase(store, L).

然后您将使用查询:

| ?- store([a, is, near, b, that, is, near, c, that, is, near, d]).

true ? ;

no
| ?- listing(edge).

% file: user_input

edge(a, b).
edge(b, c).
edge(c, d).

yes
| ?-

您也可以使用 DCG 提取到列表:

extract([edge(A,B)|Edges]) --> [A], is_near(B), and_near(B, Edges).

and_near(_, []) --> [].
and_near(A, [edge(A,B)|Edges]) --> [that], is_near(B), and_near(B, Edges).

is_near(A) --> [is, near, A].

extract(L, Edges) :-
    phrase(extract(Edges), L).

| ?- extract([a,is,near,b,that,is,near,c,that,is,near,d], Edges).

Edges = [edge(a,b),edge(b,c),edge(c,d)] ? a

no
| ?-