Finding a specific sequence of elements in a list, prolog - list

I have to write a predicate that takes a List and succeeds if the list contains elements "a, b, c"in that order anywhere in the list, other wise it fails. I am pretty lost on where to start(not looking for a solution, just a hint to the right direction).

Declarative wording
Almost always, when a Prolog task is formulated in a rather imperative way, the solution will be comparatively limited. This means that we typically can only use it in a few modes and directions, while other modes may even yield wrong results.
Therefore, I suggest to use more declarative wording.
You say:
a predicate that takes a list and succeeds if the list contains elements "a, b, c" in that order anywhere in the list, otherwise it fails.
That's a rather procedural way to look at this. Note that in Prolog, any argument can also be a logical variable, and thus there may not even be a list to "take". Instead, we expect the predicate to generate such lists in these cases!
Watch your wording! Very often, when you are able to express the task declaratively, an elegant and general Prolog solution will be straight-forward and often follows quite naturally from the task description.
Describing solutions
First, let us focus on what holds. There is no need to express what doesn't hold, because the predicate will not succeed anyways in such cases.
What do we want to describe?
Essentially, we want to describe lists of the form [...,a,b,c,...].
There are already some answers, with various drawbacks.
A pure way to do it uses the meta-predicate if_/3 from Indexing dif/2:
abc([X,Y,Z|Vs]) :-
if_((X=a,Y=b,Z=c), true, abc([Y,Z|Vs])).
Generality
This works in all directions. First, let us try the most general query, where the single argument is a fresh variable:
?- abc(Vs).
Vs = [a, b, c|_5032] ;
Vs = [a, b, a, b, c|_5144] ;
Vs = [a, b, a, b, a, b, c|_5286] .
Thus, we can generate solutions, which is a very nice property of a relation!
The predicate is monotonic, and therefore iterative deepening is possible to fairly enumerate answers:
?- length(Vs, _), abc(Vs).
Vs = [a, b, c] ;
Vs = [a, b, c, _11600] ;
Vs = [a, a, b, c] ;
Vs = [_11982, a, b, c],
dif(_11982, a) ;
Vs = [a, b, c, _11600, _11606] .
From this, it follows that there are no solutions with less than 3 elements. In this case, that's quite obvious. In other cases, such results may be much less obvious from the task description.
Efficiency
The predicate is deterministic if its argument is sufficiently instantiated.
For example:
?- abc([a,b,c]).
true.
?- abc([z,a,b,c]).
true.
?- abc([a,b,c,z]).
true.
Note that no choice points remain in these cases!

Here are three approaches you could take, in roughly ascending order by flexibility:
First, is to use the predicate nth0/3 to find the position of a, b, and c in the list, and then check that the position of a < position of b < position of c. For multiple instances of a, b, and c in the list (e.g. [c,b,a,b,c,a]) nth0 will find positions of each matching element in turn, such that if there are three positions that fit the criteria (even if they are not the first positions) the predicate will succeed.
Hint 1.1: The syntax for nth0 to find the position of a.
nth0(PositionA,[c,b,a,b,c,a],a)
Hint 1.2: The syntax of less than (for completeness)
PositionA < PositionB
Partial Solution 1: A sequence of commands using nth0 to check that a, b, and c appear in some order in the list [c,b,a,b,c,a] (assembling the predicate is left to you)
nth0(PositionA,[c,b,a,b,c,a],a),
nth0(PositionB,[c,b,a,b,c,a],b),
nth0(PositionC,[c,b,a,b,c,a],c),
PositionA < PositionB,
PositionB < PositionC.
Second approach uses list pattern matching - we observe that, when going down the list, we must encounter a, then b, then c. To do that, we can construct three predicates that find a, b, and c, and then pass on the rest of the list where appropriate. We must construct these predicates to ignore other elements until they see their target.
Hint 2.1: The head of a predicate where a is the first element of the list
find_a([a|Rest]) :-
Hint 2.2: The head of a predicate where anything is the first element of the list
find_a([_|Rest]) :-
Hint 2.3: When we find a, we start looking for b
find_a([a|Rest]) :-
find_b(Rest).
Hint 2.4: When we don't find a, we keep looking for a
find_a([_|Rest]) :-
find_a(Rest).
Hint 2.5: Order matters (kind-of)
If we place find_a([a|Rest]) first in the knowledge base then Prolog will always try to unify against it first, so we'll match the first a we find. If we place it second, this will still work, but with a lot of extra backtracking, and we'll find each a in reverse order.
Hint 2.6: Don't forget the base case!
Remember that, even though you don't need to do anything once you find c, you still need to create a fact stating that it is the head of the list: find_c([c|_]).
The third approach is essentially a generalised version of the second approach - instead of creating predicates to find a, b, and c, you create a predicate that finds a list of elements in order.
Hint 3.1: Your predicate should take two lists and compare the heads of each
compare([A|Targets],[B|Checks]) :-
Hint 3.2: If the same variable name appears in multiple places, it must have the same value for the predicate to match
compare([A|Targets],[A|Checks]) :- % succeeds when the same element is at the head of each list
Hint 3.3: If they match, keep going down both lists
compare(Targets,Checks).
Hint 3.4: If they don't match, only go down the Checks list
compare([A|Targets],Checks).
Hint 3.5: Never forget the base case (when there are no more targets)
compare([],_).
Hint 3.6: As before, ordering is still important
compare([A|Targets],[A|Checks]) :- ... should be in the knowledge base before compare(Targets,[_|Checks]) :- ...
Solution 3:
compare([],_).
compare([A|Targets],[A|Checks]) :-
compare(Targets,Checks).
compare(Targets,[_|Checks]) :-
compare(Targets,Checks).
Hope this helps!

Another way to describe the relation uses a grammar. You are talking about a sequence, well, that's what the dcg formalism is for!
:- set_prolog_flag(double_quotes, chars).
abcsubsequence(Cs) :-
phrase(abc, Cs).
abc -->
..., "abc", ... .
or alternatively, if you permit further text in between:
abc -->
..., "a", ..., "b", ..., "c", ... .
So what is this magic ...? It's just any sequence:
... --> [] | [_], ... .
Efficiency-wise mat's solution is much better. But for correctness reasons above versions are better since they fail for abcsequence([a,b,c|non_list]). However, making relations a tiny bit more general by permitting such solutions is quite common in Prolog, you just have to be aware of it.

Finding a,b,c
To find the letters a,b,c in a list in that order one should start with the comment by #lurker which says [X, Y, Z | T].
has_abc([a,b,c|T]).
Since I am using SWI-Prolog and prefer not to receive the warning
Warning: somecode.pl:
Singleton variables: [T]
I will make a small change by changing T to _
has_abc([a,b,c|_]).
and then run some simple test
?- has_abc([a,b,c]).
true.
?- has_abc([a,b,c,z]).
true.
?- has_abc([z,a,b,c]).
false.
As you can see the predicate has_abc can find a,b,c at the start of a list but not any place else.
Taking a list a part
In Prolog a list can be recursively deconstructed using [H|T]
deconstruct_list([Head|Tail]) :-
write('Head of list: '),write(Head),nl,
deconstruct_list(Tail).
and a few demonstration cases
?- deconstruct_list([]).
false.
?- deconstruct_list([a]).
Head of list: a
false.
?- deconstruct_list([a,b]).
Head of list: a
Head of list: b
false.
?- deconstruct_list([a,b,c]).
Head of list: a
Head of list: b
Head of list: c
false.
Putting the predicates together
Now combining the first two predicates for finding a,b,c and deconstructing a list gives us
has_abc([a,b,c|_]).
has_abc([_|T]) :-
has_abc(T).
and a few test cases
?- has_abc([]).
false.
?- has_abc([a]).
false.
?- has_abc([a,b]).
false.
?- has_abc([a,b,c]).
true .
?- has_abc([z,a,b,c]).
true .
?- has_abc([a,b,c,z]).
true .
?- has_abc([z,a,b,c,z]).
true .
Resolving the choice-point with a cut
Almost there. There is a small problem because for the true answers we had to press Enter to exit which indicates we have a choice-point.
A way to fix this is with a cut (!) which say that once we have an answer stop looking for more answers.
has_abc([a,b,c|_]) :- !.
has_abc([_|T]) :-
has_abc(T).
and a few test cases
?- has_abc([]).
false.
?- has_abc([a]).
false.
?- has_abc([a,b]).
false.
?- has_abc([a,b,c]).
true.
?- has_abc([z,a,b,c]).
true.
?- has_abc([a,b,c,z]).
true.
?- has_abc([z,a,b,c,z]).
true.
?- has_abc([d]).
false.
?- has_abc([d,e]).
false.
?- has_abc([d,e,f]).
false.
?- has_abc([d,e,f,g]).
false.
Notice that when running the test cases one did not have to press Enter to end the query.
Resolving the choice-point without a cut
See the answer by mat

Related

SWI-prolog : how to make a circular list by using some facts

loop1(a).
loop1(b).
loop1(c).
loop1(d).
circular(d, a).
circular(b, c).
circular(b, d).
circular(a, b).
so when I call:
in_cycle(a, Cycle).
it will return:
[a,b,d,a]
if I call:
in_cycle(b, Cycle).
it will return:
[b,d,a,b].
however, if you call:
in_cycle(c, Cycle).
it will return:
false. (because no loop is included).
here is my try:
in_cycle(C,Cycle) :- circular(C,Cycle1),in_cycle(Cycle1,Cycle).
I know this predicate has very serious problem : it won't stop...I really want to know what kind of base case I should add so this predicate will stop ? Should i add a condition so prolog will stop when it find the same alphbet ?
It would be grateful if someone could help me!
-------updated-------
check([Y,_|Z]) :- check([Y|Z]).
in_cycle(C, [C]).
in_cycle(C, [C, C1|Cycle]) :- circular(C, C1),check([C,C1|Cycle]),
in_cycle(C1, [C1|Cycle]).
What is the shortest cycle you could have in your fact database? Would circular(a, a). be cycle [a]? Knowing what the shortest cycle is might help you find (one of) the finishing condition(s) for your predicate.
To be able to find a list, your predicate needs to build it. Your in_cycle/2 never mentions any lists. You need to use the [Head | Tail] construct somewhere in there to be able to add elements to a list.
You already know something about what your cyclical list looks like. The first and last element are the same, and they are the same as the symbol you're trying to find the cycle for. Use that information.
To be able to tell when you completed a cycle, you need to remember which symbol you started with. To be able to do that with recursion, you need to keep state. So you're going to need an additional predicate where you keep that state. E.g. something involving a predicate like in_cycle(Current_symbol, Cycle, Start_symbol). You can then call that from your in_cycle/2.
Let's have a look at your try:
in_cycle(C, Cycle) :-
circular(C, Cycle1),
in_cycle(Cycle1, Cycle).
You can use the trace command at the prompt to see what's happening: trace, in_cycle(a, X).
Press Space to step through your program. Press h for help, and a to exit. Use notrace. to get out of trace mode again.
As you step through this, you'll find that your predicate is nicely looping through the cycle, but at no point does the X ever become a list. That's bad.
Let's try and make this build a list. As I mentioned in point (3), you already know something about the list. The first element of the list is the same as the first argument to in_cycle. Even more, the second element of the list is the same as the element you'll find with circular/2. So we know a cycle has at least two elements. How about this?
in_cycle(First, [First, Next|Cycle]) :-
circular(First, Next),
in_cycle(Next, [Next|Cycle]).
If you trace this now, you'll see something is happening with X, but still not actually anything useful. Cycle remains a mystery and we're just looping through the facts forever. You need some end condition here. Let's try a simple one:
in_cycle(First, [First]).
in_cycle(First, [First, Next|Cycle]) :-
circular(First, Next),
in_cycle(Next, [Next|Cycle]).
Whoa! in_cycle(a, X) suddenly gives results! All possible lists using circular connections starting with a, it seems. That's not exactly what we want, but maybe we're getting closer?
One problem with this is that in_cycle(Next, [Next|Cycle]) is not actually correct!
If you do in_cycle(a, X), you already know that X should become [a, b, d, a], so filling those values into in_cycle(First, [First, Next|Cycle]), you get:
First = a
Next = b
Cycle = [d, a]
When you get to in_cycle(Next, [Next|Cycle]), that means it's in_cycle(b, [b, d, a]). But [b, d, a] is not a cycle! You need to be able to distinguish these two situations somehow. One way of doing that is to call a separate predicate like I mentioned in (4) to keep track of what your starting element was.
A node is in a cycle, if you can find a path back to that very node. Using path/4:
in_cycle(C, [C|Cs]) :-
circular(C, A),
path(circular, Cs, A,C).
Now, does this predicate terminate? How can we test this in a systematic manner? How can we ensure that we do not forget any special case? For pure, monotonic programs as this one, testing for termination is trivial1: Simply take the most general query! That is:
?- in_cycle(C, Cs).
C = d, Cs = "dabd" % [d,a,b,d]
; C = b, Cs = "bdab"
; C = a, Cs = "abda"
; false. % it terminates!
(See this answer how to get "bdab" in place of [b,d,a,b]).
What is so nice in Prolog is that above query constitutes a proof of termination. Each query you can pose is included in above query. And since the more general query already terminates, any more specific query will terminate too! Any!
And all of this holds even for any variable free facts for circular/2. However, this proof cannot be carried out so easily as the proof for a specific set of facts.
1 Note that trivial means belonging to the trivium.

Checking if the difference between consecutive elements is the same

I am new to using arithmetic in Prolog.
I’ve done a few small programs, but mostly involving logic. I am trying to implement a function that will return true or false if the difference between every consecutive pair of elements is the same or not.
My input would look like this: sameSeqDiffs([3, 5, 7, 9], 2)
I feel like I need to split the first two elements from the list, find their difference, and add the result to a new list. Once all the elements have been processed, check if the elements of the new list are all the same.
I’ve been taught some Prolog with building relationships and querying those, but this doesn’t seem to fit in with Prolog.
Update1: This is what I've come up with so far. I am brand new to this syntax and am still getting an error on my code, but I hope it conveys the general idea of what I'm trying to do.
diff([X,Y|Rest], Result):-
diff([Y,Z|Rest], Result2):-
Result2 = Result,
Z - Y = Result.
Update2: I know I still have much to do on this code, but here is where I will remain until this weekend, I have some other stuff to do. I think I understand the logic of it a bit more, and I think I need to figure out how to run the last line of the function only if there is at least two more things in the rest of the list to process.
diff([X,Y|Rest], Result):-
number(Y),
Y-X=Result,
diff([Rest], Result).
Update3: I believe I have the function the way I want it to. The only quirk I noticed is that when I run and input like: sameSeqDiffs([3,5,7],2).I get true returned immediately followed by a false. Is this the correct operation or am I still missing something?
sameSeqDiffs([X,Y], Result):-
A is Y - X,
A = Result.
sameSeqDiffs([X,Y,Z|T], Result):-
sameSeqDiffs([Y,Z|T], Result).
Update 4: I posted a new question about this....here is the link: Output seems to only test the very last in the list for difference function
Prolog's syntax
The syntax is a bit off: normally a clause has a head like foo(X, Y, Z), then an arrow (:-), followed by a body. That body normally does not contain any arrows :-. So the second arrow :- makes not much sense.
Predicates and unification
Secondly in Prolog predicates have no input or output, a predicate is true or false (well it can also error, or got stuck into an infinite loop, but that is typically behavior we want to avoid). It communicates answers by unifying variables. For example a call sameSeqDiffs([3, 5, 7, 9], X). can succeed by unifying X with 2, and then the predicate - given it is implemented correctly - will return true..
Inductive definitions
In order to design a predicate, on typically first aims to come up with an inductive definition: a definition that consists out of one or more base cases, and one or more "recursive" cases (where the predicate is defined by parts of itself).
For example here we can say:
(base case) For a list of exactly two elements [X, Y], the predicate sameSeqDiffs([X, Y], D) holds, given D is the difference between Y and X.
In Prolog this will look like:
sameSeqDiffs([X, Y], D) :-
___.
(with the ___ to be filled in).
Now for the inductive case we can define a sameSeqDiffs/2 in terms of itself, although not with the same parameters of course. In mathematics, one sometimes defines a function f such that for example f(i) = 2×f(i-1); with for example f(0) = 1 as base. We can in a similar way define an inductive case for sameSeqDiffs/2:
(inductive case) For a list of more than two elements, all elements in the list have the same difference, given the first two elements have a difference D, and in the list of elements except the first element, all elements have that difference D as well.
In Prolog this will look like:
sameSeqDiffs([X, Y, Z|T], D) :-
___,
sameSeqDiffs(___, ___).
Arithmetic in Prolog
A common mistake people who start programming in Prolog make is they think that, like it is common in many programming languages, Prolog add semantics to certain functors.
For example one can think that A - 1 will decrement A. For Prolog this is however just -(A, 1), it is not minus, or anything else, just a functor. As a result Prolog will not evaluate such expressions. So if you write X = A - 1, then X is just X = -(A,1).
Then how can we perform numerical operations? Prolog systems have a predicate is/2, that evaluates the right hand side by attaching semantics to the right hand side. So the is/2 predicate will interpret this (+)/2, (-)/2, etc. functors ((+)/2 as plus, (-)/2 as minus, etc.).
So we can evaluate an expression like:
A = 4, is(X, A - 1).
and then X will be set to 3, not 4-1. Prolog also allows to write the is infix, like:
A = 4, X is A - 1.
Here you will need this to calculate the difference between two elements.
You were very close with your second attempt. It should have been
samediffs( [X, Y | Rest], Result):-
Result is Y - X,
samediffs( [Y | Rest], Result).
And you don't even need "to split the first two elements from the list". This will take care of itself.
How? Simple: calling samediffs( List, D), on the first entry into the predicate, the not yet instantiated D = Result will be instantiated to the calculated difference between the second and the first element in the list by the call Result is Y - X.
On each subsequent entry into the predicate, which is to say, for each subsequent pair of elements X, Y in the list, the call Result is Y - X will calculate the difference for that pair, and will check the numerical equality for it and Result which at this point holds the previously calculated value.
In case they aren't equal, the predicate will fail.
In case they are, the recursion will continue.
The only thing missing is the base case for this recursion:
samediffs( [_], _Result).
samediffs( [], _Result).
In case it was a singleton (or even empty) list all along, this will leave the differences argument _Result uninstantiated. It can be interpreted as a checking predicate, in such a case. There's certainly no unequal differences between elements in a singleton (or even more so, empty) list.
In general, ......
recursion(A, B):- base_case( A, B).
recursion( Thing, NewThing):-
combined( Thing, Shell, Core),
recursion( Core, NewCore),
combined( NewThing, Shell, NewCore).
...... Recursion!

Prolog union fails

I'm trying to understand the use of union (the built in predicate) in Prolog. In many cases it seems to fail when it should succeed. It seems it has something to do with the order of the elements of the lists. All of the below cases fail (they come back with "false.").
?- union([1,2,3],[],[2,3,1]).
?- union([1,5,3], [1,2], [1,5,3,2]).
?- union([4,6,2,1], [2], [1,2,4,6]).
?- union([1,2], [], [2,1]).
Shouldn't all of these be true? Any explanation as to why these cases keep failing would be very helpful.
Also: Why does the below not succeed and find the correct list for A?
?- union([1,5,3], A, [4,1,5,3,2]). /** comes back with "fail." */
There are a couple of issues here. Declarative and procedural ones. Let's start with the declarative ones, they are really sitting a bit deeper. The procedural aspects can be handled easily with appropriate programming techniques, as in this answer.
When we consider declarative properties of a predicate, we consider its set of solutions. So we pretend that all we care about is what solutions the predicate will describe. We will completely ignore how all of this is implemented. For very simple predicates, that's a simple enumeration of facts - just like a database table. It is all obvious in such situations. It becomes much more unintuitive if the set of solutions is infinite. And this happens so easily. Think of the query
?- length(Xs,1).
This harmless looking query asks for all lists of length one. All of them! Let me count - that's infinitely many!
Before we look at the actual answer Prolog produces, think what you would do in such a situation. How would you answer that query? Some of my feeble attempts
?- length(Xs,1).
Xs = [1]
; Xs = [42]
; Xs = [ben+jerry]
; Xs = [feel([b,u,r,n])]
; Xs = [cromu-lence]
; Xs = [[[]]]
; ... . % I am running out of imagination
Should Prolog produce all those infinitely many values? How much time would this take? How much time do you have to stare at walls of text? Your lifetime is clearly not enough.
Taming the number of solutions, from solutions to answers
There is a way out: The logic variable!
?- length(Xs, 1).
Xs = [_A].
% ^^
This little _A permits us to collapse all strange solutions into a single answer!
So here we really had a lot of luck: we tamed the infinity with this nice variable.
Now back to your relation. There, we want to represent sets as lists. Lists are clearly not sets per se. Consider the list [a,a] and the list [a]. While they are different, they are meant to represent the same set. Think of it: How many alternate representations are there for [a]? Yep, infinitely many. But now, the logic variable cannot help us to represent all of them compactly1. Thus we have to enumerate them one-by-one. But if we have to enumerate all those answers, practically all queries will not terminate due to infinitely many solutions to enumerate explicitly. OK, some still will:
?- union([], [], Xs).
Xs = [].
And all ground queries. And all failing queries. But once we have a variable like
?- union([a], [], Xs).
Xs = [a]
; Xs = [a,a]
; Xs = [a,a,a]
; ... .
we already are deep into non-termination.
So given that, we have to make some decisions. We somehow need to tame that infinity. One idea is to consider a subset of the actual relation that leans somehow to a side. If we want to ask questions like union([1,2],[3,4], A3) then it is quite natural to impose a subset where we have this functional dependency
A1, A2 → A3
With this functional dependency we now determine exactly one value for A3 for each pair of A1, A2. Here are some examples:
?- union([1,5,3], [1,2], A3).
A3 = [5,3,1,2].
?- union([1,2,3], [], A3).
A3 = [1,2,3].
Note that Prolog always puts a . a the end. That means Prolog says:
Dixi! I have spoken. There are no more solutions.
(Other Prologs will moan "No" at the end.) As a consequence, the queries (from your comments) now fail:
?- union([1,5,3], [1,2], [1,5,3,2]).
false.
?- union([1,2,3],[],[2,3,1]).
false.
So imposing that functional dependency now restricts the set of solutions drastically. And that restriction was an arbitrary decision of the implementer. It could have been different! Sometimes, duplicates are removed, sometimes not. If A1 and A2 both are duplicate free lists, the result A3 will be duplicate free, too.
After looking into its implementation, the following seems to hold (you do not need to do this, the documentation should be good enough - well it isn't): The elements in the last argument are structured as follows and in that order:
The elements of A1 that do not occur in A2, too. In the relative order of A1.
All elements of A2 in their original order.
So with this functional dependency further properties have been sneaked in. Such as that A2 is always a suffix of A3! Consequently the following cannot be true, because there is no suffix of A3 that would make this query true:
?- union([1,5,3], A2, [4,1,5,3,2]).
false.
And there are even more irregularities that can be described on a declarative level. Often, for the sake of efficiency, relations are too general. Like:
?- union([],non_list,non_list).
Such concerns are often swiped away by noting that we are only interested in goals with arguments that are either lists (like [a,b]) or partial lists (like [a,b|Xs]).
Anyway. We finally have now described all the declarative properties we expect. Now comes the next part: That relation should be implemented adequately! There again a new bunch of problems awaits us!
With library(lists) of SWI, I get:
?- union([1,2], [X], [1,2,3]).
false.
?- X = 3, union([1,2], [X], [1,2,3]).
X = 3.
Which is really incorrect: This can only be understood procedurally, looking at the actual implementation. This no longer is a clean relation. But this problem can be fixed!
You can avoid the correctness issues altogether by sticking to the pure, monotonic subset of Prolog. See above for more.
1) To tell the truth, it would be possible to represent that infinite set with some form of constraints. But the mere fact that there is not a single library for sets provided by current Prolog systems should make it clear that this is not an obvious choice.

Understanding the splitting in Swi-prolog

I have this code for splitting input list into its halves. It seems to be OK.
halve(List,A,B) :- halve(List,List,A,B), !.
halve(B,[],[],B).
halve(B,[_],[],B).
halve([H|T],[_,_|T2],[H|A],B) :-halve(T,T2,A,B).
Ok, so I tried to decode it. The beginning is clear:
"Halve took list and 2 logic variables" is this:
halve(List,A,B)
(1) Then continuous this part:
:- halve(List,List,A,B).
And this means, that I am creating new two lists (List, List) from the first one or what? What exacly represents ":-"? I guess the new lists = halves will be the A, and B, right?
(2) Second, please, I don't quite get these two lines:
halve(B,[],[],B).
halve(B,[_],[],B).
Maybe you could explain it on some examples, please?
(3) Well, I hope after your explanation of (1) and (2), I'll get the final part by myself...
halve([H|T],[_,_|T2],[H|A],B) :- halve(T,T2,A,B).
Thank you very, very much for helping me.
Ok, our first problem already has its solution. Long story short, it works like this:
halve([1,2,3,4,5],[1,2],[3,4,5]).
->true
If you notice it splits the list into its halves but if the list has an odd number of the elements, the second half is the bigger one.
Now what I want to obtain is to have the first one bigger.
So I'm thinking about this:
I'm going to reach this:
Halves_div([1,2,3],A,B).
A=[1,2],
B=[3].
Let's say my input is list: [1,2,3]. So I'll start with splitting list's head and tail: [H|T] and then I will merge the H with new empty list - my 1st Half (A).
After that I have A=[1], B=[] and Input=[2,3].
For merging I have:
merge([],List,List).
merge([H|T],List,[H|New]) :- merge(T,List,New).
And one more thing - I need to check whether the 1st half is already >= 2nd half, right?
So this is my idea and only thing I'd love you to help me is to write it in prolog. I'm kinda confused how to put it together.
Thanks!
It seems my idea of solution is too complicated and I found something better!
To start, a Prolog clause looks like that:
Head :- Body
You can read that as "Head if Body", or "Body implies Head".
Note that sometimes you just have
Head
That's because Head is always true. Instead of calling Head a clause, we rather call it a fact in this case.
So here, we have:
halve(List,A,B) :- halve(List,List,A,B).
That means that halve(List, A, B) is true if halve(List, List, A, B) is true. Concretely it's just a way to delegate the work of halve/3 to halve/4, a so called worker predicate.
Why do we need a worker predicate? Well, because here we'd like to use another variable to calculate our A and B terms. But we couldn't do that with halve/3 because the 3 argument spots of halve/3 were already taken by the input list, List, the first half of the result, A and the second half of the result, B.
About the List, List thing, it's just a way to say that we call halve/4 with the same first and second argument, like you would in any programming language.
Then the interesting stuff starts. Prolog will try to prove that halve/4 is true for some given arguments. Let's say to illustrate the execution that we called halve/3 this way:
?- halve([1, 2], A, B).
Then, if you followed what I talked about previously, Prolog will now try to prove that halve/3 is true by proving that halve/4 is true with the following arguments: halve([1, 2], [1, 2], A, B)..
To do that, Prolog has 3 choices. The first choice is the following clause:
halve(B,[],[],B).
Obviously, that won't work. Because when Prolog will try to fit the second argument of the caller "in" the second argument of the callee through unification, it will fail. Because
[1, 2] can't be unified with [].
Only two choices left, the next is:
halve(B,[_],[],B).
Same thing here, Prolog cannot unify [1, 2] and [_] because _ is just a variable (see my post about the anonymous variable _ if you've troubles with it).
So the only chance Prolog has to find a solution to the problem you presented it is the last clause, that is:
halve([H|T],[_,_|T2],[H|A],B) :- halve(T,T2,A,B).
Here, Prolog will find a way to unify thing, let's see which way:
we have to unify [1, 2] with [H|T]. That means that H = 1. and T = [2].
we have to unify [1, 2] with [_,_|T2]. that means that T2 = [].
now we start to build our results with the next unification, ie A = [H|A'] (I primed the second A because variables are scoped locally and they are not the same). Here we tell that when we'll have our result calculated from the body of the clause, we'll add H to it. Here H is 1 so we already know that the first element of A will be 1.
Ok ok, unification succeeded, great! We can proceed to the body of the clause. It just calls halve/4 in a recursive manner with those values (calculated above):
halve([2], [], A, B).
And here we start all over again. Though this time things will be fast since the first choice Prolog has will be a good fit:
halve(B,[],[],B).
can be unified to
halve([2], [], A, B).
with those values: A = [] and B = [2].
So that's a good step, we now reached the "base case" of the recursion. We just have to build our result from bottom to top now. Remember when we called recursively our predicate halve/4 a few steps above? We had already said that the first element of A would be 1. Now we know that the tail is [] so we can state that A = [1]. We hadn't stated anything particular about B so B = [2] is left untouched as the result.
Now that I detailed the execution, you might wonder, why does this work? Well, if you pay attention, you'll note that the second argument of halve/4 is gone through twice as fast as the first one. [H|T] vs [_, _|T2]. That means that when we hit the end of the list with our second argument, the first one is still at the middle of our list. This way we can divide the thing in two parts.
I hope I helped you catch some of the subtle things at work here.
halve(List,A,B) copies first half of List to A and unifies second half with B
That will be true when length of our list will be even: halve(B,[],[],B).
That will be true when length of out list will be odd: halve(B,[_],[],B).
halve([H|T],[_,_|T2],[H|A],B) :- halve(T,T2,A,B).
Here we are setting 2 lets call them 'pointers' in each step we copy one element from beginning of our list to A because we want get first half.
Because in each step we are removing 2 elements from our list [_,_|T2] Predicate will stop when list will have only one left element or empty, then it will unify rest of our list with B. If you cant understand use trace/0
This version might prove useful ...
split_in_half(Xs, Ys, Zs) :- length(Xs, Len),
Half is Len // 2, % // denotes integer division, rounding down
split_at(Xs, Half, Ys, Zs).
split_at(Xs, N, Ys, Zs) :- length(Ys, N), append(Ys, Zs, Xs).

How to find the Nth element of a list, and print said element out?

so i have a homework question that asks me to find the third element of a list, as well as the last element of a list and print them out (2 separate programs).
I Thought my Code would work to find the third element, by keeping track of a index, but i recieve a error when i try to run the code:
findthird([], Result).
findthird(List, Result) :- secondFunc(List, 0, Result).
secondFunc([Head|Tail], Count, Result) :-
Count < 3, Count is Count+1, secondFunc(Tail, Count, Result).
secondFunc([Head|Tail], Count, [Head|Result]).
Have any ideas for this?
The output i receieve now Is :
| ?- findthird([2,3,4], Result).
Result = [2|_]
yes
I am still having a tough time wrapping my head around Prolog, i just cant seem to understand it.
Any help is appreciated as always,
Thank.
Updated with new attempt code***
Updated ** This is the code that solved my problem:
findthird([], Result).
findthird(List, Result) :- secondFunc(List, 0, Result).
secondFunc([], Count, []).
secondFunc([Head|Tail], Count, Result) :-
Count1 is Count+1, Count1 < 3, secondFunc(Tail, Count1, Result).
secondFunc([Head|Tail], Count, Head).
Input:
| ?- findthird([3,4,5], Result).
Output:
Result = 5 ?
yes
Input:
| ?- findthird([3,4,5,6,7], Result).
Output:
Result = 5 ?
yes
First of all, you have to understand that in Prolog, you don't manipulate return values of function. The reason behind this is that you do not manipulate functions, but predicates. So length(List) never evaluates to a number, but to true or false, as any other predicate. When you write findelement(List, length(List), len... the findelement predicate won't be called with something like [a, b, c] and 3, it will be called with something like [a, b, c] and length([a, b, c]). So already your program cannot work.
That put aside, your program is still very wrong. The basic way a recursion works in prolog or in functional languages (as well as when you use structural induction in maths) is as follows :
a clause for initialization
a clause for heredity
In your program, you don't have an initialization clause. Meaning that when recursion hits [], no clause can handle it, and the thing fails. The rest is false too, but I think it's especially important to get the recursion principles right first.
To illustrate that without spoiling the problem for you (it's homework after all), I'll take an example : say you wanna test if a sheepfold is safe. The sheepfold is safe if there's no wolf in it. If we represent the sheepfold by a list and the wolf by the atom wolf, we can write the predicate like that :
Initialization : if the sheepfold is empty, it's safe, there's no wolf in it.
safe_sheepfold([]).
Heredity : if the sheepfold is safe with n-1 members, it's safe with n members if the added member is not a wolf :
safe_sheepfold([Animal|Sheepfold]) :-
Animal =\= wolf,
safe_sheepfold(Sheepfold).
And that's it. To see how prolog handles the request, compile this and issue a trace. command before running the predicate, as pointed out in your last question, it will help you to understand how things work.
To let you think about that with a more concrete example, here is a classic predicate, factorial (it uses arithmetic too) :
Here is our initialization clause :
factorial(0, 1).
Here is our heredity clause :
factorial(N, F) :-
N > 0,
NextN is N - 1,
factorial(NextN, NextF),
F is NextF * N.
To keep this simple I didn't make this predicate tail recursive nor used cuts, you'll learn about those things later on!
I hope my rambling will be of some help.
edit post update :
It's almost that ! Now just a few more hints : the result you want is not a list, it's just an element, so try to modify the last clause to just return the element, not a list with the element. And the initialization clause is actually your last clause here (the thing that checks if you're above 3), so you don't need the one with [] ! You're almost there :)