Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swap two items depending on the index

Tags:

prolog

I have a predicate like this:

swap(List, Index1, Index2, New_List).
List = [3,8,1,6].
Index1 = 1.
Index2 = 3.

With the swap, New_List will be:

New_List = [3,6,1,8].

I'm trying to implement some code, but I don't understand why It gives me: False.

Could you help me to understand why my code is wrong, and how can I fix it?

Code:

swap([],_,_,[]).

swap(List, Index1, Index2, New_List) :-
    swap(List, 0, Index1, Index2, New_List),
    print(New_List).

swap([],_,_,_,[]).
swap(List, Index, Index1, Index2, [H|R]) :-
    Index \== Index1,
    nth0(Index, List, H, _Rest),
    Index_New is Index+1,
    swap(List, Index_New, Index1, Index2, R).

swap(List, Index, Index1, Index2, [H|R]) :-
    Index == Index1,
    nth0(Index2, List, H, _Rest),
    Index_New is Index+1,
    swap(List, Index_New, Index1, Index2, R).

swap(List, Index, Index1, Index2, [H|R]) :-
    Index == Index2,
    nth0(Index1, List, H, _Rest),
    Index_New is Index+1,
    swap(List, Index_New, Index1, Index2, R).

Thank you.

like image 444
Jack23 Avatar asked Dec 15 '25 07:12

Jack23


1 Answers

You can use tracing to see exactly what happens. Like this:

?- trace.
true.

[trace]  ?- swap([3,8,1,6], 1, 3, R).
   Call: (10) swap([3, 8, 1, 6], 1, 3, _13242) ? /* Press 'h' */ Options:
+:                  spy        -:              no spy
/c|e|r|f|u|a goal:  find       .:              repeat find
a:                  abort      A:              alternatives
b:                  break      c (ret, space): creep
[depth] d:          depth      e:              exit
f:                  fail       [ndepth] g:     goals (backtrace)
h (?):              help       i:              ignore
l:                  leap       L:              listing
n:                  no debug   p:              print
r:                  retry      s:              skip
u:                  up         w:              write
m:                  exception details
C:                  toggle show context
   Call: (10) swap([3, 8, 1, 6], 1, 3, _13242) ? creep
   Call: (11) swap([3, 8, 1, 6], 0, 1, 3, _13242) ? creep
   Call: (12) 0\==1 ? creep
   Exit: (12) 0\==1 ? creep
   Call: (12) lists:nth0(0, [3, 8, 1, 6], _13830, _13990) ? creep

You can use 'c' to "creep" through the rest of the evaluation of your predicate and try to understand how it is different from what you expected to happen.

For example, I don't understand why you need the extra argument, the 0, and so on, if you already chose to use nth0/4. I am using the nth0/4 that I find in SWI-Prolog.


This should be enough:

swap(L, A, B, Result) :-
    nth0(B, L, Y, L0),
    nth0(A, L0, X, L1),
    A < B,
    nth0(A, L2, Y, L1),
    nth0(B, Result, X, L2).

The order of the indexes with regard to each other is important. Also the order of the swapping is important, if you don't want to recalculate the indexes. You can even enumerate the two indexes:

?- swap([a,b,c], A, B, R).
A = 0,
B = 1,
R = [b, a, c] ;
A = 0,
B = 2,
R = [c, b, a] ;
A = 1,
B = 2,
R = [a, c, b] ;
false.

This still does not terminate for this query:

?- swap(List, A, B, Swapped).

This would be a pretty hairy thing to get absolutely right. Does it need to work in this mode? EDIT: see the answer by Isabelle Newbie.

like image 140
TA_intern Avatar answered Dec 16 '25 23:12

TA_intern