Prolog: working with lists - list

I got this assignment with Prolog lists and I need some help.
Build a program in Prolog that
Check if a list is empty
Check if a list is not empty
Check if a list only has one element
Check if a list has 2 or more elements
Get the first element from a list
Get the second element from a list
Get a list without the first element (tail)
Add an element to the head of the list

It sounds like you are the very beginning of prolog. These questions mostly relate to how prolog unifies variables and expressions.
Check if a list is empty
empty([]).
In prolog, you state facts and predicates. Here, you are simply stating that any empty list is true. It is implied that all other expressions are false.
Check if a list is not empty
not_empty([_|_]).
(Improved by lurker). This rule matches a list that has at least a head and zero or more tail elements, so empty list would fail.
Check if a list only has one element
one([_]).
When prolog checks this fact, it can only bind to a list with one element. So the fact it bound already proves it is a one element list.
Check if a list has 2 or more elements
two([_,_|_]).
The first 2 underscores bind to 2 elements in the list, the 3rd underscore to zero or more trailing elements. So this will only evaluate to true on lists with two or more elements.
Get the first element from a list
first([H|_], H).
Prolog will bind H to the first element of the list in the first argument and the second argument. You call it with first([1,2,3],F).. Prolog will bind F to the first element of the list. You can also call it with first([1,2,3],1). to ask if 1 is the first element.
Get the second element from a list
second([_,I|_], I).
Just using simple binding, the first underscore binds with the first element, I with the second element, and the second underscore with the rest of the list, (if any). If you start asking for much higher elements, it is easier to use built-in predicates like nth1 to do the work for you.
Get a list without the first element (tail)
tail([_|T],T).
Prolog binds the tail to T, which must match the second T to be considered true.
Add an element to the head of the list
addelem(H,T,[H|T]).
Just using Prolog binding, the H will be bound to the front of the list in the 3rd argument, and T to the tail of the list. Call with
addelem(1,[2,3,4],T). — Binds T to [1,2,3,4].
addelem(1,[2,3,4],[1,2,3,4]). — Proves that this result is correct.
addelem(H, [2,3,4], [1,2,3,4]). — Pulls the first element of the 3rd argument, if the second argument matches the tail.
addelem(1, T, [1,2,3,4]). — another way of getting the tail, if the head is 1.

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.

What is the term for the first N elements of a list?

The first element of a list is called a head, and the rest of a list is its tail. But what is the term for a sublist that consists of first N elements of a list? And what is the name for the rest of the list after N'th element?
Actually, in a rather large subset of linked list implementations, the tail is actually the last element rather than the list sans the head :-)
Since there appears to be little consensus (after two years) as to what you should call the initial subset, you can name it whatever you like as long as it's clear, for example:
initial subset of size N;
first N elements;
initial-N.
I would actually call the rest of the list just the remainder, since you'll almost always be using it in the context of what you're discussing.
So, for example, the head has a remainder of all but the head, and the initial subset of size N has a remainder of the list minus those N elements.

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.

Define new list and recursively add items in the list by appending in Prolog

I am trying to do some operation on the given list items and trying to declare a new list and add items to it that satisfy a certain condition. I have to call this function recursively. So, first time the list is null and i want to insert an item in it. Second time , it will have one element and adding another element makes two elements. Third time two elements are there, and add one more element and so on.
Please help me how to declare list in prolog and addr elements to it by appending in recursive function calls.
There is no need to declare terms in Prolog; they exist once you write them down. So if you write [], it is the empty list. The things you mention are relations between two lists: One list, call it List0, and another list, call it List, which is List0 with additional elements. So you have a relation like
list0_list(List0, List) :-
....
which holds if List is List0 with the elements you want. You only have to describe when this relation holds, and you do this by stating the necessary conditions in the rule's body.

How to concat lists in erlang without creating nested lists?

I'm trying to be a good erlanger and avoid "++". I need to add a tuple to the end of a list without creating a nested list (and hopefully without having to build it backwards and reverse it). Given tuple T and lists L0 and L1:
When I use [T|L0] I get [tuple,list0].
But when I use [L0|T], I get nested list [[list0]|tuple]. Similarly, [L0|L1] returns [[list0]|list1].
Removing the outside list brackets L0|[T] produces a syntax error.
Why is "|" not symmetric? Is there a way to do what I want using "|"?
| is not "symmetric" because a non-empty list has a head and a tail where the head is a single item and the tail is another list. In the expression [foo | bar] foo denotes the head of the list and bar is the tail. If the tail is not a proper list, the result won't be a proper list either. If the head is a list, the result will simply be a list with that list as its first element.
There is no way to append at the end of a linked list in less than O(n) time. This is why using ++ for that is generally shunned. If there were special syntax to append at the end of the list, it would still need to take O(n) time and using that syntax wouldn't make you any more of a "good erlanger" than using ++ would.
If you want to avoid the O(n) cost per insertion, you'll need to prepend and then reverse. If you're willing to pay the cost, you might just as well use ++.
A little more detail on how lists work:
[ x | y ] is something called a cons cell. In C terms it's basically a struct with two members. A proper list is either the empty list ([]) or a cons cell whose second member is a proper list (in which case the first member is called its head, and the second member is called its tail).
So when you write [1, 2, 3] this creates the following cons cells: [1 | [2 | [3 | []]]]. I.e. the list is represented as a cons cell whose first member (its head) is 1 and the second member (the tail) is another cons cell. That other cons cell has 2 as its head and yet another cons cell as its tail. That cell has 3 as its head and the empty list as its tail.
Traversing such a list is done recursively by first acting on the head of the list and then calling the traversal function on the tail of the list.
Now if you want to prepend an item to that list, this is very easy: you simply create another cons cell whose head is the new item and whose tail is the old list.
Appending an item however is much more expensive because creating a single cons cell does not suffice. You have to create a list that is the same as the old one, except the tail of the last cons cell must be a new cons cell whose head is the new element and whose tail is the empty list. So you can't append to a list without going through the whole list, which is O(n).