Reverse the last two elements of a list in Prolog - list

I am trying to write the following predicate in Prolog while not making use of append/3:
lastTwoReversed(List, ListOf2)
which succeeds exactly when ListOf2 contains the last and the second-to-last elements of List in that order (i.e. reversed).
However, I don't know where to start. Any help is appreciated.

You can write a simple recursive predicate with a base case pattern matching on a list consisting of two elements like so:
last_two_reversed([X,Y],[Y,X]).
Since this is probably homework, I think it's best if you try to write the recursive clause yourself.

Simply use the built-in predicate reverse/2:
last_two_reversed([A,B|T],[Y,X]) :-
reverse([A,B|T],[Y,X|_]).
This will fail for lists with strictly less than two elements. A sensible thing to do would be to make it succeed using those two additional rules:
last_two_reversed([],[]).
last_two_reversed([H],[H]).

First of all, the predicate should fail or succeed with empty list or list with only one element??
In mathematical logic the predicate should return true with empty list and one-element list, because there are no last and second to-last elements to reverse.
So if you want to succeed with empty or one element list you should first start with :
lastTwoReversed([],[]).
lastTwoReversed([X],[X]).
(else don't write the above rules).
Next as base you should write:
lastTwoReversed([X,Y],[Y,X]).
and finally for list of length 3 or greater:
lastTwoReversed([X,Y,Z|T],[X|T1]):-lastTwoReversed([Y,Z|T],T1).
Keep in mind that we write [X,Y,Z|T] to specify for list with 3 or more elements so that doesn't match the previous rules.

Related

How to make predicate repeat N number of times in Prolog?

I have a number of lists containing letters and I have written a predicate that checks whether or not there are duplicates present in one of these given lists:
noDuplicates([]).
noDuplicates([H|T]):-
not(member(H, T)),
noDuplicates(T).
I have 10 lists and I want to know if there are no duplicates in any of them, so I made them into sublists of one big list, something like:
[[A,B,C], [C,A,D], [E,F,G]...]]
(So there can be duplicates in the big list, but not the individual sublists).
I get that I have to do the duplicates test 10 times; once for every sublist, but how do I write this in Prolog? I could probably write it down 10 times, but my guess is I can use recursion to make prolog repeat itself until all sublists have been checked.
So basically: I want this predicate to repeat itself N times, until N is 10. I'm really struggling with it though. Does anyone have any idea on what to do?
Let us generalize the question as follows:
You have a predicate p/1 that expresses what you want for a single list.
Thus, to lift this definition to a list of such lists, you can define a predicates ps/1 as follows:
ps([]).
ps([L|Ls]) :-
p(L),
ps(Ls).
Every time you see this pattern, you can use maplist/2. That is, the above is equivalent to:
ps(Ls) :- maplist(p, Ls).
The goal maplist(p, Ls) is true iff p holds for each element L of Ls.
Note that it will limit your understanding of Prolog if you think in terms of "looping" and "repeating". These are imperative notions and only make sense when the list is already fully instantiated. However, from Prolog, we expect more than that: We expect a full-fledged relation to also generate lists for which the relation holds. And in such cases, there is nothing to "repeat" yet: We start from nothing, and ask Prolog what solutions there are in general.
Thus, think in terms of describing when the relation ps/1 holds for lists of lists:
It holds for the empty list [].
It holds for the list [L|Ls] if our initial predicate (p/1) holds for L, and ps/1 holds for the remaining list Ls.
This declarative reading is applicable in all directions, no matter how many list elements are already instantiated, if any. It works for 10 lists just as well as for zero and 50.

Prolog: Checking lengths of lists inside a list

I'm totally new in Prolog and I have problems handling a list that contains other lists.
I have some lists like this:
[([5],23),([1],23),([2],43),([4],29),([3],14),([5,1,4,3],47)]
and I am trying to take the (sub)list with the biggest length and put it first at the list
in this example I want the result to be like this:
([5,1,4,3],47),([5],23),([1],23),([2],43),([4],29),([3],14)]
(don't care whether it will be removed or not from it's starting place).
Thanks to all who will try to help
Presuming that you want to use the built-in sort routine (I'm using SWI-Prolog as example here), then the following would work:
calcLen((List,K),(N,List,K)):- length(List,N).
delLen((_,List,K),(List,K)).
sortlen(List,Sorted):-
maplist(calcLen,List,List1),
sort(0,#>=,List1, List2),
maplist(delLen,List2,Sorted).
The two predicates calcLen and delLen insert and remove a length calculation at the front of the pairs in the list -- making them triples. The maplist predicate applies calcLen (and later delLen) to a list.

Prolog - Modifying and returning list

I want to define predicate which takes a list, adds an element to the list, let's say the number "1", and then returns the list.
I've found out I can add elements to a list using append/3, but I want to use in inside another predicate, thus why I want it to return "my modified list".
My object-oriented mindset tells me to ask the interpreter something like: ?-append(X,5,X). , so that it takes the list X, adds 5 to it, and returns "the new X", but I know that's not how unification works, so my mind is kinda in a glitch.
Can anyone please try to explain how something like this could be achievable?
You are already very close to the solution, so I only rephrase what you are beginning to sense already:
First, you cannot modify a list in pure Prolog.
Instead, you should think in terms of relations between entities. In your case, think in terms of relations between lists.
So, "adding the number 1" to a list is a relation between two lists, which could look like this:
list_with_one(Ls, [1|Ls]).
Note that this works in all directions! You can use it to:
generate answers
test particular cases
"reverse" the direction etc.
So, all you need to do in your case is to think in terms of relations between lists: One without an element, and how this relates to a different list with the element.
Obviously, these two lists will be indicated by different variables and different arguments.
Note in particular that append(X, 5, X) cannot hold: First of all, append/3 is meant to be a relation between lists, and 5 is not a list. Second, assuming you wrote for example append(Xs, [5], Xs), then this would be true if there where a list Xs such that if the element 5 were appended to Xs, the resulting list would again be Xs. Good luck finding such a list... Note also the naming convention to denote lists by letting the variable name end with an s.
It is also falls a bit short to blame this on your "object-oriented mindset", since you can have object oriented programming in Prolog too.
Although lists in Prolog cannot be modified, it is possible to add elements to the end of a list with an unspecified length. In this way, items can be "appended" to a list without creating another list:
:- initialization(main).
append_to_list(List,Item) :-
append_to_list(List,Item,0).
append_to_list(List,Item,Index) :-
% using SWI-Prolog's nth0 predicate
(nth0(Index,List,Check_Item),
var(Check_Item),
nth0(Index,List,Item));
(Next_Index is Index+1,
append_to_list(List,Item,Next_Index)).
main :-
A = [1,2,3|_],
append_to_list(A,4),
append_to_list(A,7),
writeln(A).
In this example, A becomes [1,2,3,4,7|_].

Prolog lists splitting

I have function:
onlySecond([],[]).
onlySecond([H1,H2|T1],[H2|T2]) :- onlySecond(T1,T2).
It returns every second element in the list.
But i'm curious why it is not returning nothing (on my opinion, it must return [] - empty list) when first argument is list with 1 element. Example:
onlySecond([1],X). - not return anything.. but why it doesn't return []??
Your program has a bigger problem: it returns false for any list of odd size. The reason for it is that there is no clause of onlySecond/2 that would unify with a list that has exactly one item - a condition that you would necessarily reach when you start with a list that has an odd number of items, because each recursive invocation reduces the length of the original list by two:
it does not unify with the first clause, because [1] is not an empty list
it does not unify with the second clause, because [1] has fewer than two items.
In order to fix this problem, add a separate clause to deal with a list that has exactly one item:
onlySecond([_], []).
Adding this clause makes your code work for lists of odd length as well.
Demo.

OCAML - Is element in the list?

let's say we have a list of elements:
[(a,b); (c,d); (e,f)]
What function would check if element (lets say A, where A=(x,y)) is in the list or not?
Use List.mem to do the search for a match.
let a = (3,4)
List.mem a [(1,2); (3,4); (5,6)]
You can also use List.memq if you want to check if the two items both reference the same entity in memory.
Here's a hint on how to write this yourself. The natural way to to process a list is to initially look at the first element, then check the remainder of the list recursively until you have an empty list. For this problem, you could state the algorithm in English as follows:
If the list is empty then the item is not in the list,
else if the first list element equals the item then it is in,
else it is the answer to (Is the item in the remainder of the list?)
Now you just need to translate this into OCaml code (using a recursive function).
In general, if you can describe what you want to do in terms of smaller or simpler parts of the problem, then writing the recursive code is straightforward (although you have to be careful the base cases are correct). When using a list or tree-structured data the way to decompose the problem is usually obvious.