2017-02-26 93 views
1

我想出来的行使下列事实在抽象谓词

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). 

开始...并要求读者定义谓词travel/3这样,例如,

travel(valmont, losAngeles, T) 

...会找到像这样的解决方案

T = go(byCar(valmont, metz), 
     go(byTrain(metz, paris), 
      go(byPlane(paris, losAngeles)))). 

这是我想到的:

travel(X,Y,go(byCar(X,Y))):-byCar(X,Y). 
travel(X,Y,go(byTrain(X,Y))):-byTrain(X,Y). 
travel(X,Y,go(byPlane(X,Y))):-byPlane(X,Y). 

travel(X,Z,go(byCar(X,Y),T)):-byCar(X,Y),travel(Y,Z,T). 
travel(X,Z,go(byTrain(X,Y),T)):-byTrain(X,Y),travel(Y,Z,T). 
travel(X,Z,go(byPlane(X,Y),T)):-byPlane(X,Y),travel(Y,Z,T). 

看来工作...

?- travel(valmont, losAngeles, X). 
X = go(byCar(valmont, saarbruecken), go(byTrain(saarbruecken, paris), go(byPlane(paris, losAngeles)))) ; 
X = go(byCar(valmont, metz), go(byTrain(metz, paris), go(byPlane(paris, losAngeles)))) ; 
false. 

...但它伤害了我的眼睛;所有这些重复都是抽象的呼喊。

我试图通过定义

oneLeg(X,Y):-byCar(X,Y);byTrain(X,Y);byPlane(X,Y). 

...并重新定义,以消除重复travel/3

travel(X,Y,go(oneLeg(X,Y))):-oneLeg(X,Y). 
travel(X,Z,go(oneLeg(X,Y),T)):-oneLeg(X,Y),travel(Y,Z,T). 

...但结果还没有应用:

?- travel(valmont, losAngeles, X). 
X = go(oneLeg(valmont, saarbruecken), go(oneLeg(saarbruecken, paris), go(oneLeg(paris, losAngeles)))) ; 
X = go(oneLeg(valmont, metz), go(oneLeg(metz, paris), go(oneLeg(paris, losAngeles)))) ; 
false. 

我该如何强制更换结果中第oneLeg个实例e具体的byCar,byTrainbyPlane那“证明”oneLeg实例?

+1

查看高级谓词的'call/N'系列。在你的情况下,'call/3'将特别有用。另外,'(= ..)/ 2'也值得一看。 – mat

+0

@mat:谢谢,但是我无法弄清楚你的建议...... – kjo

+0

如果你没有分成三个不同的表格,但有一个表格有三个参数:从,到,意味着一切都会更容易。然后,如果突然你还需要乘船出海或类似的东西,你不必改变你的计划。 – 2017-03-03 12:40:14

回答

3

firstACommentOnNamingThingsasInJavaByMixingTheCasesWhichIsHardToReadyou_may_find_even_long_names_very_readable_when_using_underscores

其次,Prolog是一个非常动态语言,你可以很容易地使用call/N家人元谓词和其他高阶谓词像  (=..)/2构建和调用任意关闭。

在你的榜样,首先考虑改变谓词的名字,以适应命名通常的Prolog的惯例,使用强调分隔单词:

 
by_car(auckland, hamilton). 
by_car(hamilton, raglan). 
by_car(valmont, saarbruecken). 
by_car(valmont, metz). 

by_train(metz, frankfurt). 
by_train(saarbruecken, frankfurt). 
by_train(metz, paris). 
by_train(saarbruecken, paris). 

by_plane(frankfurt, bangkok). 
by_plane(frankfurt, singapore). 
by_plane(paris, los_angeles). 
by_plane(bangkok, auckland). 
by_plane(singapore, auckland). 
by_plane(losAngeles, auckland). 

现在,合适的抽象可能是谓语means/1,这我们可以这样定义:

 
means(plane). 
means(train). 
means(car). 

这是很容易使用这个动态调用合适的谓词:

使用此
 
by_means(From, To, Means) :- 
     means(Means), 
     atom_concat(by_, Means, Pred), 
     call(Pred, From, To). 

一种方法看起来是这样的:

 
route(To, To) --> []. 
route(From, To) --> [Step], 
     { by_means(From, Next, Means), 
      Step =.. [Means,From,Next] }, 
     route(Next, To). 

样品的查询和答案:

 
?- phrase(route(valmont, los_angeles), Rs). 
Rs = [car(valmont, saarbruecken), train(saarbruecken, paris), plane(paris, los_angeles)] ; 
Rs = [car(valmont, metz), train(metz, paris), plane(paris, los_angeles)] ; 
false. 

这项工作的关键在于手段的系统化的命名约定,书信等方式谓词。在这种情况下,对应关系是动态构建的,以便一次说明几个概念。为了提高效率,灵活性和甚至可能的安全性,您当然也可以通过静态的Prolog事实对通信本身进行编码。例如:

 
means_predicate(plane, by_plane). 
means_predicate(train, by_train). 
means_predicate(car, by_car). 

by_means(From, To, Means) :- 
     means_predicate(Means, Pred), 
     call(Pred, From, To). 
+1

额外的感谢。我从你的答案中学到了大量的Prolog。 – kjo

+1

不客气!作为一个练习,考虑写一个也避免使用'(= ..)/ 2'的版本! – mat

+0

我对Prolog不太了解,但你为什么要做动态的事情,而'= ..'和'call'呢?难道不可能使用像康涅狄格州(汽车,奥克兰,哈密尔顿)或康恩(飞机,法兰克福,新加坡)这样的单一桌子吗?或者Prolog和关系数据库有很大的不同? – 2017-03-03 12:43:58

2

如果我必须这样做,我可能会尝试将汽车和平面以及火车转换为单一表from_to_means。我发现你可以这样做,如下所示:

forall(byCar(From, To), assertz(from_to_means(From, To, car))) 

然后相同的飞机和火车。在SWI-Prolog的也有短期的扩展,所以也许你可以插入三个原始表

term_expansion(byCar(From, To), from_to_means(From, To, car)). 

与同为飞机和火车的上方。

然后,您只需评估from_to_means(From, To, Means)或者如果您编写from_to_means(From, To, train),则只能选择一种运输工具。

+2

这是问题的一部分(好)替代解决方案。然而,它并没有解释如何解决第二个问题:你如何将这些谓词的解决方案转化为形式为[car(valmont,metz),train(metz,paris),plane(paris,los_angeles)]'的列表,这是我在答案的第二部分中展示的。为此,您需要再次使用不同的表示法,表中的冗余数据,或者使用'(= ..)/ 2'。很显然,当你可以自由地重组表格时,你可以使表格更加统一。 +1表示一个很好的替代表示! – mat

+0

你好@mat,谢谢你的客气话。我真的不知道Prolog足够好评判。我认为数据结构及其在屏幕上的显示方式更为独立,但如果您不想单独打印到屏幕上,您似乎总是需要更多代码才能将一个数据结构映射到另一个数据结构。 – 2017-03-06 07:58:58