摘要谓词

时间:2017-02-26 17:15:51

标签: prolog meta-predicate

我正在尝试的练习从以下事实开始

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的实例,并使byCarbyTrainbyPlane替换oneLeg {{1}}实例?

2 个答案:

答案 0 :(得分:3)

firstACommentOnNamingThingsasInJavaByMixingTheCasesWhichIsHardToReadyou_may_find_even_long_names_very_readable_when_using_underscores

其次,Prolog是一种非常强大的动态语言,您可以使用call/N元谓词系列和其他高阶谓词(如{{}轻松构造和调用任意闭包。 1}}。

在您的示例中,请考虑首先更改谓词名称以符合通常的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).

现在,一个合适的抽象可能是谓词(=..)/2,我们可以这样定义:

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 :(得分: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),则只能选择一种传输方式。