Reputation: 84
I have to complete a problem, in which, one task is to get consecutive pairs of an array.
For example, if the array is [1, 2, 3], the result should be X=1 Y=2 and X=2 Y=3
Until this moment my code works fine, but after that, it doesn't output 'no'. Instead, it sticks in an infinite loop. The hard part is that I have to do this without recursion.
My code so far is the following:
part_of(X, Y, List):-
length(X, 1),
append(_, X, Part),
length(Y, 1),
append(Part, Y, Part2),
append(Part2, _, List).
I'm not familiar with logic programming. Everything that goes through my mind have to do with returning values, which of course, is not the case here.
Upvotes: 0
Views: 474
Reputation: 9378
X
and Y
are consecutive elements of some List
if List
is of the following form: some Prefix
list, then X
, then Y
, then some Rest
list.
This is kind of what you were trying to express, but you got confused on some details. First, the one-element list containing X
is written as [X]
. This is probably what you were trying to say with length(X, 1)
, but that wouldn't work as written.
Second, you got confused with your uses of append/3
. The way you are trying to use it, the last argument is the whole list that you are trying to decompose. So in this scenario, the third argument should always be a list that is already known -- either because it is passed in as an argument, or because it was computed by an earlier goal. In your code, the first append/3
goal is append(_, X, Part)
, where both _
and Part
are unknown. Under these circumstances there is an infinite number of solutions, which causes the nontermination you see:
?- append(_, X, Part).
X = Part ;
Part = [_G2897|X] ;
Part = [_G2897, _G2903|X] ;
Part = [_G2897, _G2903, _G2909|X] ;
Part = [_G2897, _G2903, _G2909, _G2915|X] ;
Part = [_G2897, _G2903, _G2909, _G2915, _G2921|X] .
In short, you have the right idea, but the order of binding things isn't quite right. The following works:
?- List = [1, 2, 3], append(Prefix, Part1, List), append([X], Part2, Part1), append([Y], Rest, Part2).
List = Part1, Part1 = [1, 2, 3],
Prefix = [],
X = 1,
Part2 = [2, 3],
Y = 2,
Rest = [3] ;
List = [1, 2, 3],
Prefix = [1],
Part1 = [2, 3],
X = 2,
Part2 = [3],
Y = 3,
Rest = [] ;
false.
This first splits the known list List
= [1, 2, 3]
into its parts, of which there are only finitely many. This binds Part1
to a finite list. Then it splits the finite list Part1
, binding Part2
to a finite list, and finally it splits that. There is no room for nontermination if the initial List
is a finite list.
All that said, there is an easier way of expressing "some list, then two adjacent elements X
and Y
, then some other list":
?- append(_Prefix, [X, Y | _Rest], [1, 2, 3]).
_Prefix = [],
X = 1,
Y = 2,
_Rest = [3] ;
_Prefix = [1],
X = 2,
Y = 3,
_Rest = [] ;
false.
Upvotes: 3
Reputation: 117027
Here is how I would do this:
pairs([X,Y|_],X,Y).
pairs([_,Y|T],A,B) :- pairs([Y|T],A,B).
The first predicate succeeds when it can get a pair of elements from the start of a list.
The second predicate succeeds when it can strip the first element from the list and recursively call pairs/2
to get a subsequent pair.
Here's the output of my run:
?- pairs([a,b,c],X,Y).
X = a,
Y = b ;
X = b,
Y = c ;
false.
Upvotes: 0
Reputation: 377
Here is my very simple solution.
show_elements([X|[]], _, _).
show_elements([X, Y|Q], A, B):- A is X, B is Y; show_elements([Y|Q], A,B).
Here is a photo of the output, I don't know if I correctly understood the task.
As you can see, I used recursion to solve the problem. Make sure you correctly understand recursion. It's used a lot in Prolog.
Also check the concept of unification. It is necessary to start writing programs in Prolog.
There is a lot of material online, and you can check this very useful guide: Lean Prolog now!
Upvotes: -1