Пролог: Реверс каждого второго элемента списка - PullRequest
0 голосов
/ 14 мая 2011

Мне нужно написать программу, которая получит списки в списке, и должна будет переворачивать каждый второй список, а затем возвращать результат.Примерно так:

doStuff([[1,2], [3,4], [5,6], [7,8]], R).

R = [[1,2], [4,3], [5,6], [8,7]]

Это то, что я имею до сих пор:

doStuff([],_).
doStuff([X,S|T],R):- reverse(S,Rev), add(X,Rev,R), doStuff(T,R).
doStuff([X|[]], R):- add(X,R,R).

reverse([X|Y],Z,W) :- reverse(Y,[X|Z],W).
reverse([],X,X).

add(X,[],X).
add(X,L,[X,L]).

Моя проблема в том, что во второй итерации функция добавления завершается ошибкой.Я также обеспокоен тем, что произойдет, когда исходный список будет содержать только один список в конце.

1 Ответ

0 голосов
/ 14 мая 2011

, так как вы сказали, что add / 3 завершается неудачно после второй итерации, я предполагаю, что вы в любом случае использовали trace / 0
, вот оно:

[trace]  ?- doStuff([[1,2], [3,4], [5,6], [7,8]], R).
   Call: (6) doStuff([[1, 2], [3, 4], [5, 6], [7, 8]], _G405) ? creep
   Call: (7) lists:reverse([3, 4], _G496) ? creep
   Exit: (7) lists:reverse([3, 4], [4, 3]) ? creep
   Call: (7) add([1, 2], [4, 3], _G405) ? creep
   Exit: (7) add([1, 2], [4, 3], [[1, 2], [4, 3]]) ? creep
   Call: (7) doStuff([[5, 6], [7, 8]], [[1, 2], [4, 3]]) ? creep
   Call: (8) lists:reverse([7, 8], _G514) ? creep
   Exit: (8) lists:reverse([7, 8], [8, 7]) ? creep
   Call: (8) add([5, 6], [8, 7], [[1, 2], [4, 3]]) ? creep
   Fail: (8) add([5, 6], [8, 7], [[1, 2], [4, 3]]) ? creep
   Redo: (7) doStuff([[5, 6], [7, 8]], [[1, 2], [4, 3]]) ? creep
   Fail: (7) doStuff([[5, 6], [7, 8]], [[1, 2], [4, 3]]) ? creep
   Redo: (6) doStuff([[1, 2], [3, 4], [5, 6], [7, 8]], _G405) ? creep
   Fail: (6) doStuff([[1, 2], [3, 4], [5, 6], [7, 8]], _G405) ? creep
false.

так почему же это не удается?это из-за одной из основных характеристик пролога: переменная в прологе, когда она принимает значение, она никогда не может изменить это, может показаться странным, если вы до сих пор использовали императивные языки, но учтите, что в математике происходит то же самое.
Например, рассмотрим следующие уравнения:

x+3=4  
4-x=5

из первого мы получаем, что x = 1
, а из второго мы получаем, что x = -1
, поскольку x не может быть 1 и-1 мы говорим, что x не удовлетворяет вышеприведенным уравнениям;
не то, что x равно -1, поскольку это значение второго (и последнего) уравнения

точно так же происходит в вашей программе:

doStuff([X,S|T],R):- reverse(S,Rev), add(X,Rev,R), doStuff(T,R).

, поэтому в первый раз R присваивается значение, а doStuff / 2 является вызовом со значением для R.
очевидно, это неверное значение, поэтому doStuff / 2 завершается сбоем

так как вы можете это исправить?посмотрите, как вы написали [X, S | T], чтобы отделить первые два элемента, которые вы хотели обработать.вам нужно сделать то же самое с результатом:
напишите его как [XResult, SResult | Rest], конечно, XResult будет просто X, а SResult будет противоположностью S (Rev)
Rest будет тем, чемвы получаете от рекурсивного вызова doStuff / 2

в последнюю очередь, но не в последнюю очередь вы должны проверить пункты, которые вызываются в конце.

вы можете проверить кое-что о lists и рекурсия

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...