Prolog 中的递归 - 寻找城市之间的路径
Posted
技术标签:
【中文标题】Prolog 中的递归 - 寻找城市之间的路径【英文标题】:Recursion in Prolog - Finding Path Between Cities 【发布时间】:2012-05-01 04:31:04 【问题描述】:我正在努力完成this page 底部的练习,但我发现自己对第 3 项完全感到困惑。
我们得到以下旅游信息知识库:
byCar(auckland, hamilton).
byCar(hamilton, raglan).
byCar(valmont, saarbruecken).
byCar(valmont, metz).
byTrain(metz, frankfurt).
byTrain(saarbruecken, frankfurt).
byTrain(metz, paris).
byTrain(saarbruecken, paris).
byPlane(frankfurt, bangkok).
byPlane(frankfurt, singapore).
byPlane(paris, losAngeles).
byPlane(bangkok, auckland).
byPlane(singapore, auckland).
byPlane(losAngeles, auckland).
很容易确定是否可以在两个城市之间旅行。我刚刚这样做了:
connected(X, Y) :- byCar(X, Y); byTrain(X, Y); byPlane(X, Y).
travel(X, Y) :- connected(X, Y).
travel(X, Z) :- connected(Y, Z), travel(X, Y).
但是,当我必须用变量实际统一路径时,我完全糊涂了!
这是我写的:
connected(X, Y) :- byCar(X, Y); byTrain(X, Y); byPlane(X, Y).
connected(Y, Z, Out) :- connected(Y, Z).
travel(X, Y, Out) :- connected(X, Y).
travel(A, Z, Out) :- connected(Y, Z),travel(A, Y, connected(Y, Z, Out)).
并叫travel(valmont, losAngeles,X).
在跟踪过程中,除了最后的匿名变量之外,还有一个点显示了正确的路径:
travel(valmont, metz, connected(metz, paris, connected(paris, losAngeles, _17)))
但我实际上不知道如何将其与变量 X
统一起来!
我真的无法完全解决这个问题。谁能给我一个提示只是为了把我推向正确的方向?我只是缺少一个终止条件吗?
编辑:
现在我有:
connected(X,Y) :- byCar(X,Y);byTrain(X,Y);byPlane(X,Y).
go(X,Y) :- connected(X,Y).
travel(X,Y,go(X,Y)) :- connected(X,Y).
travel(A,Z,Path) :- travel(Y,Z,Path),go(A,Y,Path).
go(A,Y,Path) :- travel(A,Y,Path).
但它会像这样卡住:
4 4 Exit: byPlane(paris,losAngeles) ?
3 3 Exit: connected(paris,losAngeles) ?
2 2 Exit: travel(paris,losAngeles,go(paris,losAngeles)) ?
5 2 Call: go(metz,paris,go(paris,losAngeles)) ?
6 3 Call: travel(metz,paris,go(paris,losAngeles)) ?
7 4 Call: travel(_217,paris,go(paris,losAngeles)) ?
8 5 Call: travel(_242,paris,go(paris,losAngeles)) ?
9 6 Call: travel(_267,paris,go(paris,losAngeles)) ?
10 7 Call: travel(_292,paris,go(paris,losAngeles)) ?
我玩过它,但我无法用它来构建整个 go(a,b,go(b,c))
等...
【问题讨论】:
【参考方案1】:一位病理学家通过以下方式向我解释了这一点:
您的目标是获得 X = go(valmont,metz,go(metz,paris,go(paris,losAngeles))) 以响应查询 travel(valmont,losAngeles,X)。
要解决这个问题,你的 travel/3 谓词需要有 From、To 和 Path,但它必须以没有 Path 的简单 go(From, To) 结尾。简单的 go(From, To) 是你的 travel/3 的基本条件,所以:
travel(X, Y, go(X, Y)) :- connected(X, Y).
这和拉尔斯曼所说的完全一样。
现在,您需要创建递归 travel/3 谓词:
travel(X, Y, go(X, Z, Path)) :-
connected(X, Z),
travel(Z, Y, Path).
你的 go/2 谓词是多余的,而且有点令人困惑,因为 travel/3 谓词有一些看起来像 go 谓词的东西。通过删除 go/2 谓词,代码更易于阅读和理解。
【讨论】:
【参考方案2】:我会给你递归的基本情况:
travel(X, Y, go(X, Y)) :- connected(X, Y).
递归的情况看起来非常相似,除了您正在构建的 go/3
术语必须将位置作为其前两个参数,并将路径(另一个 go/2
或 go/3
术语)作为其第二个参数。
【讨论】:
但是我不应该用路径作为第三个参数来构建一个 go/3 吗? @JPTG:除了基本情况,是的。 (在示例的末尾更仔细地查看。)在其他情况下,第一个 2 项将与 go/2 中的一样,第三个将是路径。我可能已经定义了问题,因此基本案例也是 go/3,带有一个空列表或一些诸如基本案例之类的列表,但这只是我。 @JohnPeterThompsonGarcés:哎呀,是的,我的意思是go/3
,我说的是go/2
。
All:这些 go/3 术语不好。并非没有原因@larsmans 忘记添加最后一个参数:某物的列表(无论是城市还是 go_by(From,To,Medium))绝对是更可取的。
我不应该使用列表来解决这个问题。到目前为止,我有:connected(X,Y) :- byCar(X,Y);byTrain(X,Y);byPlane(X,Y). go(X,Y) :- connected(X,Y). travel(X,Y,go(X,Y)) :- connected(X,Y). travel(A,Z,Path) :- travel(Y,Z,Path),go(A,Y,Path). go(A,Y,Path) :- travel(A,Y,Path).
,但我不知道如何处理第二个循环的 travel(X,Y,go(X,Y)) ——它不会统一。这让我觉得我采取了完全错误的方法。以上是关于Prolog 中的递归 - 寻找城市之间的路径的主要内容,如果未能解决你的问题,请参考以下文章