我有这个程序:
pathloop
除了Path
基本运行之外,一切都运行但是递归必须显示一个列表?- can_call(asd, dsa, Route)
,其中包含从A到B的路径。但是当我运行程序并输入{{1}时},
它失败了(返回false
。)。我必须在pathloop
上改变什么?我试过了
?- pathloop(1, 5, [], Path).
并显示10-20个结果,然后显示false
。
答案 0 :(得分:1)
我尝试了
?- pathloop(1,5,[],Path).
,它显示了10-20个结果,然后是false
。
让我们详细看看答案并突出显示任何虚假部分......
?- pathloop(1,5,[],Path). Path = [1,4,5] % ok ; Path = [1,4,5,8,5] ; Path = [1,4,5,8,9,12,15,10,7,6,3,5] ; Path = [1,4,5,3,5] ; Path = [1,4,5,3,6,7,10,15,12,9,8,5] ; Path = [1,4,8,5] % ok ; Path = [1,4,8,9,12,15,10,7,6,3,5] % ok ; Path = [1,4,8,5,3,5] ; Path = [1,2,1,4,5] ; Path = [1,2,1,4,5,8,5] ; Path = [1,2,1,4,5,8,9,12,15,10,7,6,3,5] ; Path = [1,2,1,4,5,3,5] ; Path = [1,2,1,4,5,3,6,7,10,15,12,9,8,5] ; Path = [1,2,1,4,8,5] ; Path = [1,2,1,4,8,9,12,15,10,7,6,3,5] ; Path = [1,2,1,4,8,5,3,5] ; false.
当前状态: 20个答案中的17个无效!
要解决此问题,我们使用meta-predicate path/4
:
?- path(connect,Path,1,5). Path = [1,4,5] ; Path = [1,4,8,9,12,15,10,7,6,3,5] ; Path = [1,4,8,5] ; false.
确定!接下来,我们调整can_call/3
的定义以使用path/4
代替pathloop/4
:
can_call(PersonA, PersonB, Route) :- telephone(_-Area1-_, name(PersonA, _)), telephone(_-Area2-_, name(PersonB, _)), path(connect,Route,Area1,Area2).
但是当我运行[...]
?- can_call(asd,dsa,Route).
时,它会失败(返回false
。)
让我们使用新版can_call/3
重新运行查询以上!
?- can_call(asd,dsa,Route).
Route = [6,7,10,15,12]
; Route = [6,3, 5, 8, 9,12]
; Route = [6,3, 5, 4, 8, 9,12]
; false.
有效!
答案 1 :(得分:0)
问题在于,当您在pathloop/4
中拨打can_call/3
时,您会将未接地的变量_
传递给Visited
。换句话说,您提供了一个未经实例化的列表。现在,如果您执行成员检查member(a,X)
并X
这样未实例化,它会说," 是的!这是可能的,只需制作X=[a|_]
"。
因此,为了解决此问题,请将can_call/3
重写为:
can_call(PersonA, PersonB, Route) :-
telephone(_-Area1-_, name(PersonA, _)),
telephone(_-Area2-_, name(PersonB, _)),
pathloop(Area1, Area2,[Area1], Route).
从那时起,您只访问过Area1。
我认为将基本案例定义为到达目的地更有意义:
pathloop(End,End, _,[End]) :-
!.
" 剪切" (!
)禁用以下事实:一旦到达目的地,您将继续搜索循环。例如,如果您想要从4
连接到5
。它不会提出类似4 -> 5 -> 8 -> 4 -> 5
的路由,因此在到达后会循环。
接下来,归纳案例会搜索Next
(我不会将其称为Middle
,因为它不是中间的节点,而是位于开头旁边的节点。
pathloop(Start, End, Visited,[Start|Path]) :-
connect(Start, Middle),
\+ member(Middle, Visited),
pathloop(Middle, End,[Middle|Visited],Path).
最好不要使用统一X=[A|B]
,如果这些已经可以在头部进行。它允许更快的执行,特别是如果你以相反的方向调用谓词。