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结果中的实例替换为特定byCarbyTrain, 或byPlane“证明”oneLeg实例?

4

2 回答 2

3

firstACommentOnNamingThingsasInJavaByMixingTheCasesWhichIsHardToRead: you_may_find_even_long_names_very_readable_when_using_underscores.

其次,Prolog 是一种极其动态的语言,您可以使用call/N元谓词家族和其他高阶谓词(如 (=..)/2.

在您的示例中,考虑首先更改谓词名称以适应通常的 Prolog 命名约定,使用下划线分隔单词:

by_car(奥克兰,汉密尔顿)。
by_car(汉密尔顿,插肩)。
by_car(瓦尔蒙特,萨尔布吕肯)。
by_car(瓦尔蒙特,梅斯)。

by_train(梅茨,法兰克福)。
by_train(萨尔布吕肯,法兰克福)。
by_train(梅茨,巴黎)。
by_train(萨尔布吕肯,巴黎)。

by_plane(法兰克福,曼谷)。
by_plane(法兰克福,新加坡)。
by_plane(巴黎,洛杉矶)。
by_plane(曼谷,奥克兰)。
by_plane(新加坡,奥克兰)。
by_plane(洛杉矶,奥克兰)。

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

手段(平面)。
手段(火车)。
指(汽车)。

使用它来动态调用合适的谓词很容易:

by_means(从,到,手段):-
        手段(手段),
        atom_concat(by_, 均值, Pred),
        呼叫(预测,从,到)

使用它的一种方法可能如下所示:

路线(到,到)-> []。
路线(从,到)-> [步骤],
        { by_means(From, Next, Means),
          步骤 =.. [意味着,从,下一个] },
        路线(下一个,到)。

示例查询和回答:

?- 短语(路线(瓦尔蒙特,洛杉矶),卢比)。
Rs = [汽车(瓦尔蒙特,萨尔布吕肯),火车(萨尔布吕肯,巴黎),飞机(巴黎,洛杉矶)];
Rs = [汽车(瓦尔蒙特,梅斯),火车(梅斯,巴黎),飞机(巴黎,洛杉矶)];
错误的。

其关键在于系统的命名约定和手段与谓词的对应关系。在这种情况下,动态构造对应关系以同时说明几个概念。为了提高效率、灵活性甚至安全性,您当然也可以通过静态 Prolog 事实对通信本身进行编码。例如:

意味着_谓词(平面,by_plane)。
意味着_谓词(火车,by_train)。
意味着_谓词(汽车,by_car)。

by_means(从,到,手段):-
        mean_predicate(均值,预测),
        呼叫(预测,从,到)
于 2017-02-26T22:07:41.837 回答
2

如果我必须这样做,我可能会尝试将 byCar、byPlane 和 byTrain 转换为一个表 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)

于 2017-03-03T12:53:46.793 回答