Abstracting over predicates
我正在尝试的一个练习从以下事实开始
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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). |
...并要求读者定义一个谓词
1 | travel(valmont, losAngeles, T) |
...会找到像
这样的解决方案
1 2 3 | T = go(byCar(valmont, metz), go(byTrain(metz, paris), go(byPlane(paris, losAngeles)))). |
这是我想出的:
1 2 3 4 5 6 7 | 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). |
它似乎工作......
1 2 3 4 | ?- 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. |
...但它伤害了我的眼睛;所有这些重复都是对抽象的呐喊。
我试图通过定义
来消除重复
1 | oneLeg(X,Y):-byCar(X,Y);byTrain(X,Y);byPlane(X,Y). |
...并将
1 2 | 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). |
...但结果还不完全:
1 2 3 4 | ?- 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. |
如何强制将结果中的
其次,Prolog 是一种极其动态的语言,您可以使用
在您的示例中,首先考虑更改谓词名称以适应通常的 Prolog 命名约定,使用下划线分隔单词:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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). |
现在,一个合适的抽象可能是谓词
1 2 3 | means(plane). means(train). means(car). |
很容易使用它来动态调用合适的谓词:
1 2 3 4 |
一种使用方式可能如下所示:
1 2 3 4 5 | route(To, To) --> []. route(From, To) --> [Step], { by_means(From, Next, Means), Step =.. [Means,From,Next] }, route(Next, To). |
示例查询和回答:
1 2 3 4 | ?- 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 事实对通信本身进行编码。例如:
1 2 3 4 5 6 7 | 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). |
如果我必须这样做,我可能会尝试将 byCar、byPlane 和 byTrain 转换为一个表,from_to_means。我发现您可以像这样手动执行此操作:
1 |
然后对于飞机和火车也是如此。在 SWI-Prolog 中还有术语扩展,所以也许你可以在三个原始表上方插入
1 | term_expansion(byCar(From, To), from_to_means(From, To, car)). |
飞机和火车也一样。
那么你只需要评估