Penultimate match making cases - list

def penultimate(l:List[Int]):Int = l match{
case x::y::Nil => x
case x::tail => penultimate(tail)
case _ => ???
}
The penultimate is the element that precedes the last element in a list.
In the first case, we have a list of 2 elements. Which is the base case?
The second case, we will call recursively the same method on the tail of the list. And the number of elements in the list will decrease per one for every recursive call.
What exactly is the last case? When will the 3rd case ever occur?

The last case will occur if the initial list has fewer than 2 elements.

So, like you explained yourself, if there are two elements in the list, the first case matches.
Otherwise, if there are one or more, it is the second case?
What's left? Last case matches empty lists. If there is no first element to chop off, it will fall through the second case, and hit the last one. You can leave ??? there or throw some other exception if you prefer. Or just do l.head (it'll throw for you).
I figure, you are just writing this function for exercise, but just thought I'd mention it anyway: what you are doing is equivalent to l.init.last

Related

Reverse the last two elements of a list in Prolog

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.

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.

Prolog Recursion with lists

I am having a difficult time understand recursion in prolog. I can read examples and sometimes understand, but I mostly have a difficult time implementing them. For example, could someone code me how to find the summation all the elements in a list, and go through it? and tips on how to approach a question like this? Thanks!
A general "good" explanation is not possible, because a good explanation needs to link to the previous knoledgment of the person. I'm going, by example, assume you are able to made a "proof by induction".
Step1: Let start by the initial fact, "the sum of a set with a single element is the element itself". In prolog:
sum([A],A).
Step2: if the sum of a set Q is SQ, the sum of this set adding one element H is H+SQ. In prolog:
sum([H|Q],R) :- sum(Q,SQ), R is H+SQ.
thats all, you have the problem solved. But...
In general, we try to start by the most basic set, the empty one, so replace "step 1" that becames now: the sum of the elements of an empty set is 0:
sum([],0).
Finally, prolog is more efficiente if the rules are tail recursive (if the execution environment is not able to optimice by itself). That means a little change:
sum([],R,R).
sum([H|Q],SQ,R) :- T is SQ+H, sum(Q,T,R).
these rules can be understood as: Assume (assert) that sum of Q is SQ. In this case, sum of set Q plus an element H is SQ+H. The first one means, when there are no more elements in the pending set, the result is directly the acumulated sum.
Thinking recursively can be hard. See my answer to the question "Prolog programming - path way to a solution" for links to good resources on how to think recursively.
For instance, most recursive problems can be broken down into a few (1 or 2) special cases, and then, the general case. In your case — computing the sum of a list of numbers — one might look at it has having 1 or two special cases. First, you have to make a decision: What is the sum of an empty list? One might argue either that the sum of an empty list is zero, or that an empty list has no sum. Either is, arguable, a perfectly valid point-of-view.
In either event, the special cases are
[]. The empty list. The sum of the empty list is either 0, or nothing (in which case your predicate should fail.)
[100]. A list of length one. The sum of a list of length 1 is obviously that value of the first and only entry.
And the more general case:
[100,101,102]. The sum of a list of length greater than 1 can be computed by taking the value of the first item in the list and computing the sum of the remainder. Note that
The solution is defined in terms of itself, and
The problem is made smaller (by removing the 1st item from the list).
Eventually, the problem will degenerate into one of the special cases, right?
Given all that, let us suppose that we've decided that the sum of the empty list is to be 0. That means our 2nd special case (a single element list) goes away, leaving us with a solution that can be described as
The sum of an empty list is 0.
The sum of a non-empty list is computed by
removing the 1st item from the list,
computing the sum of the remaining items,
adding the value of the 1st item to the sum of the remainder.
And since prolog is a declarative language, our solution is going to be pretty much identical to the description of the solution:
sum_of_list( [] , 0 ) .
sum_of_list( [N|Ns] , S ) :-
sum_of_list(Ns,T) ,
S is T+N
.
The c

How to get the 2 last values from a list in recursion and in tail-recursion?

I need a predicate last_two(LST,Y,Z)
that assigns the last value of a list to Z
and the second-to-last to Y.
How can I do it in recursion? and how can I do it in tail-recursion?
thanks!
Here is a code with tail recursion, can I make it more efficient?
last2_2([_|[H1|[H2|T]]],Y,Z):-last2_2([H1|[H2|T]],Y,Z).
last2_2([H1,H2],H1,H2).
You could simplify the recursive case:
last2_2([_|T],X,Y) :- last2_2(T,X,Y).
This would make each recursive case faster (less pattern-matching), but causes it to go too far, and have to backtrack to get the last 2 elements. This would probably be of more benefit as the list gets longer (as the amount of backtracking is independent of the length of the list).
You could take this a step further, replacing the recursive case with:
last2_2([_,_|T],Y,Z):-last2_2(T,Y,Z).
last2_2([_,A,B],A,B).
Here, the recursive case strips off 2 elements at a time (at the cost of some more pattern-matching), and we need a second base case to handle odd-length lists.

Matching elements on 2 lists

I'm new to Prolog and I'm attempting to check if any element of the first list has a match on the second list. I think this will work recursively and I know that I have to use something like [X|Rest] to compare, then using that rest by calling the function again. The syntax does indeed stuck me, hence I am asking for help. I hope I was clear enough.
Edit: Oh, it's supposed to return false if there are no matching elements on the lists and true (can also terminate) if finds one match (at least, but one is enough, hence the suggestion to terminate, I believe you use ! for that?).
Here is a suggestion.
We recurse on the first list. The first definition is for the base case (first list empty). The second definition is for the case in which the first element of the first list is in the second one. The third case is for the remaining case, in which we have to examine the remainder of the first list.
common_elements([], L) :-
fail.
common_elements([H|T], L) :-
memberchk(H, L), !.
common_elements([H|T], L) :-
common_elements(T, L).