Абстрагируясь над предикатами

Упражнение, которое я пробую, начинается со следующих фактов

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

Другие вопросы по тегам