在序言中管理多个匹配
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
| ?-
假设您输入了一个图表描述,例如 "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
| ?-