编写一个未命名的变量

时间:2017-03-26 23:32:15

标签: prolog

我正在Prolog(gprolog)中编写一个程序在图表上进行路径查找。我将其部分基于this SO post

让我举个例子。以下是我绘制的示例图:example graph

以下是代码最初的样子:

path([Goal],Goal,Goal).
path(P,Start,Goal) :- adjacent(Start,X),
                      \+ (memberchk(X,P)),
                      (
                        Goal=X
                      ;
                        path([Start|P],X,Goal)
                      ).

无论基本情况是否多余,这都是问题所在。我想要一个

的输入风格
| ?- path(P,a,f).

对于那个输入,我会得到

的输出
P = [a,s,f]

true ?

然而,代码的问题在于memberchk。对于memberchk(a,P),它会尝试统一,调用memberchk(a,[a|_]),然后返回true。我不希望发生这种情况,因此我首先检查P是否使用var/1谓词进行实例化。因此,我的代码改为

path([Goal],Goal,Goal).
path(P,Start,Goal) :- var(P), 
                      path([],Start,Goal).
path(P,Start,Goal) :- adjacent(Start,X),
                      \+ (memberchk(X,P)),
                      (
                        Goal=X
                      ;
                        path([Start|P],X,Goal)
                      ).

现在,如果P未实例化,我们会使用空列表调用path/3我的问题是:现在我无法打印P,因为我致电path([],Start,Goal)P已不再与[]相关联。

我已尝试使用write/1谓词,但它在每一步打印出P或打印P = _26(意味着它打印未经实例化的P,而不是最终价值P)。

我希望这是一个简单的问题,我对Prolog非常陌生。

如果有类似问题,请道歉;我很乐意指出其他可以提供帮助的问题。在发布之前我搜索了SO和Google。

2 个答案:

答案 0 :(得分:2)

您需要的概念是累加器

你实际上非常接近:你意识到确实将P初始化为[],并在你递归时用[Start|P]填充它是一个有效的策略。这称为累加器,要获得最终结果,您只需要添加另一个参数

以下是您查询的新path/3谓词:

path(P, Start, Goal) :-
    path([], P, Start, Goal).

正如您所看到的,我们在此处添加[]作为path/4的第一个参数,我们将这样实现:

path(L, P, Goal, Goal) :-
    reverse([Goal|L], P).
path(L, P, Start, Goal) :- 
    adjacent(Start, X),
    \+ (memberchk(X, L)),
    path([Start|L], P, X, Goal).

第一个子句用于终止递归。一旦StartGoal参数与您指出的相同,递归应该结束。使用累加器时,这意味着我们将累加器与输出参数统一起来。但是,累加器包含相反的答案(并且没有最终目标),所以我们有reverse([Goal|L], P)

第二个子句与您编写的内容非常相似,但我们现在需要将P原样传递给recursive子句。请注意,我已删除了您在该条款中的分离,在这种情况下不需要。

完整的代码:

path(P, Start, Goal) :-
    path([], P, Start, Goal).
path(L, P, Goal, Goal) :-
    reverse([Goal|L], P).
path(L, P, Start, Goal) :- 
    adjacent(Start, X),
    \+ (memberchk(X, L)),
    path([Start|L], P, X, Goal).

答案 1 :(得分:0)

我解决了我的问题。解决方案依赖于:

  1. 跟踪受访节点
  2. 递归时,递归较小的列表
  3. 检查某些内容是否列表成员,以防止在不需要时进行统一
  4. 我的代码如下:

    connected(X,Y) :- adjacent(X,Y);adjacent(Y,X).
    
    not_member(_, []).
    not_member(X, [Head|Tail]) :- X \== Head, not_member(X, Tail).
    
    path(P,A,B):-path_helper(P,A,B,[Start]).
    
    path_helper([X,Y],X,Y,_):-connected(X,Y).
    path_helper([Goal],Goal,Goal,_).
    path_helper([Start|[Head|P]],Start,Goal,Visited):-connected(Start,Head),not_member(Head,Visited),path_helper([Head|P],Head,Goal,[Head|Visited]).