Абстрагируясь над предикатами
Упражнение, которое я пробую, начинается со следующих фактов
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
в результате с конкретным byCar
, byTrain
, или же byPlane
что "оправдывает" oneLeg
пример?
2 ответа
firstACommentOnNamingThingsasInJavaByMixingTheCasesWhichIsHardToRead
: you_may_find_even_long_names_very_readable_when_using_underscores
,
Во-вторых, Пролог является чрезвычайно динамичным языком, и вы можете легко создавать и вызывать произвольные замыкания, используя call/N
семейство мета-предикатов и другие предикаты высшего порядка, такие как (=..)/2
,
В вашем примере рассмотрите сначала изменение имен предикатов в соответствии с обычным соглашением Пролога для именования, используя подчеркивания для разделения слов:
на автомобиле (Окленд, Гамильтон). by_car (Гамильтон, Реглан). by_car (Вальмонт, Саарбрюккен). By_car (Вальмонт, Мец). by_train (Метц, Франкфурт). by_train (Саарбрюккен, Франкфурт). на поезде (Метц, Париж). by_train (Саарбрюккен, Париж). by_plane (Франкфурт, Бангкок). на самолете (Франкфурт, Сингапур). by_plane (paris, los_angeles). на самолете (Бангкок, Окленд). на самолете (Сингапур, Окленд). by_plane (Лос-Анджелес, Окленд).
Теперь подходящей абстракцией может быть предикат means/1
, который мы могли бы определить так:
средство (плоскость). средство (поезд). средство (автомобиль).
Это легко использовать для динамического вызова подходящих предикатов:
by_means (От, До, Значит):- средство (средства), atom_concat (by_, Средства, Пред), вызов (Пред, От, До).
Один из способов использовать это может выглядеть так:
маршрут (К, К) -> []. маршрут (От, До) -> [Шаг], {by_means (From, Next, Means), Step =.. [Means, From, Next] }, маршрут (далее, до).
Пример запроса и ответа:
? - фраза (маршрут (valmont, los_angeles), Rs). Rs = [автомобиль (Вальмонт, Саарбрюккен), поезд (Саарбрюккен, Париж), самолет (Париж, Лос-Анджелес)]; Rs = [автомобиль (valmont, metz), поезд (metz, paris), самолет (paris, los_angeles)]; ложный.
Ключом к этому является систематическое соглашение об именах и соответствие средств предикатам. В этом случае соответствие строится динамически, чтобы проиллюстрировать несколько концепций одновременно. Чтобы повысить эффективность, гибкость и, возможно, даже безопасность, вы, конечно, можете закодировать и саму корреспонденцию с помощью статических фактов Prolog. Например:
означает_предикат (плоскость, by_plane). означает_предикат (поезд, поезд_поезд). означает_предикат (автомобиль, by_car). by_means (От, До, Значит):- означает_предикат (значит, пред), вызов (Пред, От, До).
Если бы мне пришлось это сделать, я бы, вероятно, попытался преобразовать 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)
,