Пролог - возвращаемое значение из базового варианта - PullRequest
0 голосов
/ 26 октября 2010

Хорошо, вот сделка:

  • У меня две кучи рубашек
  • Я хочу взять случайную рубашку из каждой кучи и положить ее в новую кучу
  • Тогда достаньте новую кучу

И вот код:

mix([],[],_).
mix(P1,P2, Pile):-
    takeshirt(P1,1,Taken1,Rem1), takeshirt(P2,1,Taken2,Rem2), #Take one
    append(Pile,Taken1,New),     append(New,Taken2,NewPile),  #Put both of them
    mix(Remain1,Remain2,NewPile).

Вот как будет выглядеть результат:

1 ?- mix([a,b],[c,d],NewPile).
NewPile = [] .

Я хочу, чтобы это выглядело так:

1 ?- mix([a,b],[c,d],NewPile).
NewPile = [b, d, a, c] .

Или каков бы ни был результат.Я проверил с помощью графического отладчика и обнаружил, что, когда происходит последний вызов mix , привязки:

P1 = Taken1 = [b]
P2 = Taken2 = [c]
Pile           = [a, d]
Rem1 = Rem2 = []
New         = [a, d, b]
NewPile     = [a, d, b, c] #<--- Interresting  

Таким образом, требуемое значение находится в NewPile, когда последний вызов:

mix([],[],_). 

случается.После этого он рушится как карточный домик.

Итак, вопрос в следующем:

mix([],[],_).

Я бы хотел вернуть значение _ из базового случая, это правило mix фактически используется из более высокого экземпляра, куда я отправляю две стопки и получаю новую кучу.

Обновление:
Чтобы уточнить некоторые комментарии о правиле takehirt вот оно:

takeshirt(_,0,[],_).
takeshirt(List,Number,[Element|Taken],Remain) :- N > 0,
    length(List,Len),
    Index is random(Len) + 1,
    removeshirt_at(Element,List,Index,Remain),
    Number1 is Number - 1,
    takeshirt(Remain,Number1,Taken,Remain). 

1 Ответ

2 голосов
/ 26 октября 2010

Рассмотрим следующие модификации вашего кода:

mix([], [], []) :- !.
mix(P1, P2, Pile) :-
    takeshirt(P1, 1, Taken1, Rem1), 
    takeshirt(P2, 1, Taken2, Rem2),
    append(Taken1, Taken2, Pile0),
    mix(Rem1, Rem2, Pile1),
    append(Pile0, Pile1, Pile).

Кажется, вам нужно накопить «рубашки» (в виде списка атомов). Здесь мы рекурсивно добавляем их к третьему аргументу mix/3 (Pile), пока не будет достигнут базовый случай (первое предложение), когда оба входных списка являются пустыми списками (обратите внимание, что здесь необходим разрез ! поскольку шаблон привязки для второго предложения совпадает с первым, мы хотим его исключить). Поведение второго предложения, которое берет рубашку из каждого списка ввода для каждого шага, требует, чтобы они были одинаковой длины для начала.

Чтобы проверить это, я использовал следующее определение takeshirt/4:

takeshirt(Ps, _, [P], Rem) :-
    select(P, Ps, Rem).

Обратите внимание, что второй аргумент здесь не используется, так как select/3 используется, чтобы взять один элемент (рубашку) из списка и вернуть остаток. Отсутствие выреза (!) после select позволяет этому предикату возвращаться при выборе всех других элементов (рубашек) из списка. Если мы теперь выполним ваш пример запроса с этим определением, мы можем получить:

1 ?- mix([a,b],[c,d],NewPile).
NewPile = [a, c, b, d] ;
NewPile = [a, d, b, c] ;
NewPile = [b, c, a, d] ;
NewPile = [b, d, a, c] ;
false.

... мы можем видеть, что mix/3 перечисляет все возможные «груды» при возврате, взяв рубашку из первой стопки (первый список ввода), затем рубашку из второй стопки (второй список ввода) и т. Д. до тех пор, пока оба списка ввода не станут пустыми Если ваше определение takeshirt/4 не оставляет точек выбора (не возвращается), тогда вы можете получить только одно решение, если оно есть.

...