Split a list in prolog to atoms and integers - prolog

I am new to prolog and trying to make a predicate to separate a list in to atoms and integers but I have been try different ways for a while now but no where is there is an example on how this would be done. To me this seems like a basic thing to know in proleg yet there is no example that I can find on how this would be done.
eg:
separate([3,t,8,l,0,a,5,g,2],Atoms,Integers). Atoms = [a,g,l,t], Integers = [0,2,5,3,8]

In swi-prolog, using partition/4:
separate(List, Atoms, Integers):-
partition(integer, List, Integers, Atoms).
This assumes that every item in the list is either an integer or an atom
Sample run:
?- separate([3,t,8,l,0,a,5,g,2],Atoms,Integers).
Atoms = [t, l, a, g],
Integers = [3, 8, 0, 5, 2].

Especially if you're learning, roll your own. This also allows you to handle the edge cases. This, for instance, simply discards things other than atoms and integers:
atoms_and_ints( [] , [] , [] ) . % The empty list doesn't have any atoms or ints.
atoms_and_ints( [X|Xs] , [X|Atoms] , Ints ) :- % For a non-empty list,
atom(X), % - is the head an atom?
!, % - eliminate the choice point
atoms_and_ints(Xs,Atoms,Ints). % - add it to the atoms and recurse down.
atoms_and_ints( [X|Xs] , Atoms , [X|Ints] ) :- % Similarly,
integer(X), % - is the head an integer?
!, % - eliminate the choice point
atoms_and_ints(Xs,Atoms,Ints). % - if so, add it to the Ints and recurse down.
atoms_and_ints( [_|Xs], Atoms, Ints ) :- % If the head of the list is something else...
atoms_and_ints(Xs,Atoms,Ints). % - discard it and recurse down.

Related

I need to multiply and sum one list, the output should be like this

I need to multiply and sum one list, the output should be like this:
?- tp4([1,7,0,1,2,3,5], L).
L = [210,19,1,7,0,1,2,3,5]
First the multi, next the sum and at the end the rest of the numbers.
Here is a builing brick answer to your question since you seem to have a "where to start" problem. It is important to learn it by yourself, therefore you can conclude the correct answer by using maplist/2 and fold/4 as mentioned from David Tonhofer. But these are "advanced" predicates, so lets start from scratch and implement the base functionalities.
First: how to append elements to a list. You can either put something as a head of a list ([Head|List]) or use the predicate append/2 (which is build in but you can easily implement it by yourself). Note that variables start with a capital letter.
?- List=[1,2,3,4], Head = 0, Out=[Head|List].
Head = 0,
List = [1, 2, 3, 4],
Out = [0, 1, 2, 3, 4].
?- List2=[1,2,3,4], List1 = [0], append(List1,List2,Out).
List1 = [0],
List2 = [1, 2, 3, 4],
Out = [0, 1, 2, 3, 4].
You are be able to add elements to a list.
If you want to implement your own predicate, which works on lists, you either use the inbuild predicates or implement it yourself. We'll do the second one for the example of subtraction (all elements are subtracted from the last element).
Our predicate subtract/2 needs 2 attributes: a list (input) and a "return" value (output).
If the list has only one element ([H]), return the element. Otherwise split the list into a Head element and a Rest list ([Head|Rest]), compute the substract value for the list Rest (Tmp) and subtract Head from it:
subtract([H],[H]).
subtract([Head|Rest], Sub):-
subtract(Rest,Tmp),
Sub is Tmp - Head.
Test:
?- subtract([1,2,3,10],O).
O = 4 ;
false.
Works, not perfect but works. Now you know how to add elements to a list and have an example how to build predicated which operate on lists and use arithemtic functions. Now you can build your desired function.
You need to walk the list and compute the product and sum as you go from element to element. Given the neutral elements of the product and sum are, respectively, 1 and 0:
product_sum_list([Head| Tail], [Product, Sum, Head| Tail]) :-
product_sum_list(Tail, Head, 1, Product, 0, Sum).
Note that we're requiring the list to have at least one element. The auxiliary product_sum_list/6 performs the actual computation of the product and sum:
product_sum_list([], Last, Product0, Product, Sum0, Sum) :-
Product is Product0 * Last,
Sum is Sum0 + Last.
product_sum_list([Next| Tail], Current, Product0, Product, Sum0, Sum) :-
Product1 is Product0 * Current,
Sum1 is Sum0 + Current,
product_sum_list(Tail, Next, Product1, Product, Sum1, Sum).
By splitting the list between its head tail moving the tail to the first argument of the auxiliary predicate, we take advantage of the first argument indexing provided by the generality of Prolog systems to avoid the creation of spurious choice-points.
Sample call:
| ?- product_sum_list([1,7,0,1,2,3,5], L).
L = [0,19,1,7,0,1,2,3,5]
yes
You can achieve the same results using, as David suggested, meta-predicates for mapping and folding lists. But given that we need to compute both product and sum, the straight-forward solution is simpler and more efficient.
A common Prolog idiom is the use of a helper predicate, that takes extra arguments that maintain state. These also help you get to tail recursion so as to not consume stack.
The naive way to multiply a list might be:
multiply( [] , 0 ) . % The empty list has a product of zero.
multiply( [P] , P ) . % A list of length 1 is the value of the singleton element.
multiply( [N|Ns] , P ) :- % To compute the product of a list of length > 1...
multiply(Ns,T), % - recursively multiply the tail of the list, then
P is N * T % - multiply the head by the product of the tail
. % Easy!
Summation would be pretty much identical save for the operation involved.
[Note: given a list of sufficient length, this would eventually fail due to a stack overflow.]
Using a helper predicate (1) makes it tail recursive, meaning it won't blow up and die on a long list, and (2) will facilitate combining summation and multiplication. The 'helper' implementation looks like this:
multiply( [] , 0 ) .
multiply( [N|Ns] , P ) :- multiply(Ns,N,P).
multiply( [] , P , P ) .
multiply( [N|Ns] , T , P ) :-
T1 is T * N ,
multiply( Ns, T1, P )
.
And summation, again, is pretty much identical.
Now we can combine them to get what you want:
multiply_and_sum( [] , [0,0] ) .
multiply_and_sum( [N|Ns] , [P,S|Ns] ) :-
multiply_and_sum( Ns, N, N, P, S )
.
multiply_and_sum( [] , P, S, P, S ) .
multiply_and_sum( [N|Ns] , X, Y, P, S ) :-
X1 is X * N,
Y1 is Y + N,
multiply_and_sum( Ns, X1, Y1, P , S )
.

Sort predicate in Prolog

I am trying to figure out how sort/2 is implemented in Prolog. I would like to see how it works but I cannot find the code for it anywhere. Does somebody know how it is implemented?
In SWI-Prolog, sort/2 is a "built-in", so it's in C.
The file seems to be src/pl-lists.c of the distribution.
Here it is:
https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-list.c
At line 543:
static
PRED_IMPL("sort", 2, sort, PL_FA_ISO)
{ PRED_LD
return pl_nat_sort(A1, A2,
TRUE, SORT_ASC,
0, NULL, FALSE PASS_LD);
}
pl_nat_sort is in the same file
The comment is historically interesting:
Natural merge sort. Code contributed by Richard O'Keefe and integrated
into SWI-Prolog by Jan Wielemaker. The nice point about this code is
that it uses no extra space and is pretty stable in performance.
Richards claim it that many qsort() implementations in libc are very
slow. This isn't the case for glibc 2.2, where this performs about the
same as the previous qsort() based implementation.
Presumably Richard O'Keefe notes:
I've been using a variant of this code in a sorting utility since about
1988. It leaves the UNIX sort(1) program in the dust. As you may know,
sort(1) breaks the input into blocks that fit in memory, sorts the
blocks using qsort(), and writes the blocks out to disc, then merges the
blocks. For files that fit into memory, the variant of this code runs
about twice as fast as sort(1). Part of that is better I/O, but part is
just plain not using qsort().
Dayum. That brings back memories of writing sorting algorithms in '89.
If you just are seaching for any sorting algorithm you can always use bubblesort *cough*. It is one of the most simple and inefficient ways to sort a list, but - depending on the implementation - will run through an already sorted list in linear time. Bubblesort does not remove duplicates. This implementation does descending order:
bubblesort(List, SortedList) :-
bubbleit(List, List1),
! ,
bubblesort(List1, SortedList) .
bubblesort(List, List).
bubbleit([X,Y|Rest], [Y,X|Rest]) :-
X < Y,
! .
bubbleit([Z|Rest], [Z|Rest1]) :-
bubbleit(Rest, Rest1).
?- bubblesort([1,2,5,4,7,3,2,4,1,5,3],L).
L = [7, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1].
If you want to sort for the second element in a list [_,E|] change the the first bubbleit rule to
bubbleit([X,Y|Rest], [Y,X|Rest]) :-
X = [_,XX|_],
Y = [_,YY|_],
XX < YY,
! .
?- bubblesort([[a,3],[b,5],[c,1],[d,4]],L).
L = [[b, 5], [d, 4], [a, 3], [c, 1]].
Try searching quicksort.
Here is one link: https://www.codepoc.io/blog/prolog/4934/prolog-program-to-sort-a-list-using-quick-sort
Here is another example:-
quicksort([], []).
quicksort([X | Tail], Sorted):-
split(X, Tail, Small, Big),
quicksort(Small, SortedSmall),
quicksort(Big, SortedBig),
concatenate(SortedSmall, [X| SortedBig], Sorted).
split(X, [], [], []).
split(X, [Y| Tail], [Y | Small], Big):-
X > Y, !,
split(X, Tail, Small, Big).
split(X, [Y| Tail], Small, [Y | Big]):-
split(X, Tail, Small, Big).
concatenate([],List,List).
concatenate([Item|List1],List2,[Item|List3]) :-
concatenate(List1,List2,List3).
?-quicksort([1,7,4,3,6,5,9,8,12,1],L).
L = [1, 1, 3, 4, 5, 6, 7, 8, 9, 12]
false
The merge sort algorithm is a natural fit for Prolog. Not to mention trivial to implement in a language with recursion and lists as fundamental.
Here's a SWI Playground: https://swish.swi-prolog.org/p/swi-prolog-merge-sort.pl
merge_sort( [], [] ). % The empty list is by definition ordered
merge_sort( [X], [X] ). % So is a list of length one
merge_sort( Unsorted, Sorted ) :- % otherwise...
partition( Unsorted, L, R ) , % partition the list into 2 halves
merge_sort(L,L1), % recursively sort the left half
merge_sort(R,R1), % recursively sort the right half
merge(L1,R1,Sorted) % merge the newly-sorted halves
. % See? simple!
partition( [] , [] , [] ). % the empty list gets partitioned into two empty lists
partition( [X] , [X] , [] ). % a left of length 1 gets partitioned into itself and an empty list
partition( [X,Y|L] , [X|Xs] , [Y|Ys] ) :- % list of length 2 or more gets popped and divided between left and right halves
partition(L,Xs,Ys) % with the remainder being recursively partitioned.
. % Easy!
merge( [] , [] , [] ). % merging to empty lists is trivial
merge( [] , [Y|Ys] , [Y|Ys] ). % merging an empty list and a non-empty list is easy
merge( [X|Xs] , [] , [X|Xs] ). % merging a non-empty list and an empty list is easy
merge( [X|Xs] , [Y|Ys] , [Lo,Hi|Zs] ) :- % otherwise...
compare(X,Y,Lo,Hi), % compare the two terms, put them in collating sequence
merge(Xs,Ys,Zs) % and recursively merge the tails
. % Easy!
compare( X , Y , X, Y ) :- X #=< Y. % if X <= Y, X is Lo, and Y is Hi
compare( X , Y , Y, X ) :- X #> Y. % if X > Y, Y is Lo, and X is Hi

Prolog returning true/false instead of variable

I'm working on the very easy reverse list example in Prolog.
append(A, [], [A]).
append(A, B, [A|B]).
reverse([], ReversedList).
reverse([A,B], ReversedList) :-
reverse(B, TemporaryList),
append(A, TemporaryList, ReversedList).
append works correctly. However, when I call reverse the interpreter doesn't respond with a variable like append but instead it just write true or false.
Here's the log:
1 ?- consult('capitolo2'.pl). % file containing the code
2 ?- append(a, [b,c,d], L).
L = [a,b,c,d]. % ok, this works
3 ?- reverse([a,b,c], L).
false. % what? why that's not L = something?
The platform is SWI-Prolog 7.2 on Windows
append/3
Did you unit test it? Did it work properly? Your append/3 implementation is incorrect. The first clause
The first clause:
append( A , [] , [A] ).
simply creates a list of length 1 from its 1st argument (whatever it might be). Given that, if you said:
append( [1,2,3] , [] , X ) .
You'd get back:
X = [ [1,2,3] ]
A list of length 1, with the sole item it contains being the original 1st argument. The second clause is similarly incorrect:
append( A , B , [A|B] ).
Prepends the 1st argument — whatever it might be, and in its entirety — as the head of that list. Given that, if you said something like:
append( [1,2,3] , [a,b,c] , X ) .
You'd get back:
X = [ [1,2,3] , a , b , c ] .
A list of length 4, the first item of which is the original 1st argument.
Prolog is a descriptive language: you describe the solution and let the engine work things out. append/3 asserts that a list (the 3rd argument to append/3 represent the concatenation of the 1st argument and the 2nd argument.
Here is an implementation of append/3, simplified for clarity:
append( [] , RL , RL ) . % The concatenation of an empty left-hand list and a right hand list is the right hand list.
append( [LH|LT] , RL , CL ) :- % The concatenation of a non-empty left-hand list and a right-hand list is true IF:
CL = [LH|CT] , % - The left-hand head and the concatenation head are the same, AND
append( LT , RL , CT ) % - recursively, the concatenated tail represents the conconcatenation of the left-hand tail and the right-hand list.
. % Easy!
As you pop items off the left-hand list, it will eventually decompose into the terminating special case. This can be simplified to the classic implementation:
append( [] , RL , RL ) .
append( [LH|LT] , RL , [LH|CT] ) :- append( LT , RL , CT ) .
reverse/3
Similarly, your reverse/3 implemenation is incorrect. Your first clause:
reverse([], ReversedList).
pretty much says that pretty much anything is the reverse of the empty list. Since your ReversedList variable is never referenced, your Prolog implementation should at least throw a warning about singleton variables here. Many implementations make it an error.
Your second clause:
reverse([A,B], ReversedList) :-
reverse(B, TemporaryList),
append(A, TemporaryList, ReversedList).
says that the reverse of a 2-item list ([A,B]) is obtained by
reversing the 2nd item in the list (B), and
appending the 1st item (A) to that.
Not exactly a correct description of the solution. You might try something like
reverse( [] , [] ) . % The empty list is already reversed, what with it being atomic and all.
reverse( [H|T] , R ) :- % a non-empty list can be reversed by decomposing it into its head and tail, and
reverse(T,T1) , % - reversing the tail, and
append(T1,H,R) . % - appending the head to the now-reversed tail.
It's possible there are other problems, but
reverse([], ReversedList).
is almost surely not what you want here. The reverse of an empty list is an empty list, translates to
reverse([], []).
Additionally,
reverse([A,B], ReversedList)
is also probably not what you want. It is not a list with head A and tail B, but rather a 2-element list.

Prolog: Create list containing elements at even indices

Basically, I need to write a predicate, even_elts(L,M), such that L is a new list generated that contains only the even indexed elements from M (0th, 2nd, 4th, etc)
add_tail([X],[],X).
add_tail([H|NewT],[H|T],X) :-
add_tail(NewT,T,X).
even_elts(L,[]) :- L = [].
even_elts(L,M) :- even_elts2(L,M,1).
even_elts2(L,[H2|T2],Ct) :-
Ct2 is Ct + 1,
((Ct2 mod 2) =:= 0, add_tail(L,L2,H2), even_elts2(L2,T2,Ct2); even_elts2(L,T2,Ct2)).
even_elts2(_,[],_) :- !.
This works if M is empty or contains 1 or 2 elements. But, it only gets the first even indexed element from M, not the rest. Any pointers
EDIT: Solved the problem a different way, by removing the odd indexed elements rather than trying to create a new list and copying the data over. But, if someone can figure out a solution for my original code, I would be interested to see.
You're making this much more complicated than it is. You can use pattern matching to get each even element out, then collect those in the second (output) argument.
% an empty list does not have even elements
even_elts([], []).
% for all other lists, skip the second element (_),
% add the first to the output, recurse
even_elts([X, _ | L], [X | R]) :-
even_elts(L, R).
Just another approach with accumulator:
even_elts(L,M) :-
even_elts(M,0,[],L).
even_elts([H|T],I,Acc,Ans) :-
( I mod 2 =:= 0, append(Acc,[H], AccNew)
; I mod 2 =:= 1, AccNew = Acc
),
Inew is I + 1,
even_elts(T,Inew,AccNew,Ans).
even_elts([],_,Acc,Acc).
And
?- even_elts(X,[1,2,3,4,5]).
X = [1, 3, 5] ;
evens([A,B|C], [A|D]):- !, .....
evens(X, X).
is all you need. Fill in the blanks. :)

Why prolog outputs a weird tree-like list?

In this Prolog code I intend to list the first N primes,
(...)
biggerPrime(N,P) :-
isPrime(N),
P is N,
!.
biggerPrime(N,P) :-
N1 = N+1,
biggerPrime(N1,P).
primeListAcc(0,A,R,R) :- !.
primeList(N,L) :-
primeListAcc(N,1,[],L).
primeListAcc(N,A,L,R) :-
N1 is N-1,
biggerPrime(A,P),
A1 is P+1,
primeListAcc(N1,A1,[P|L],R).
And it works fine if I want the list ordered backwards:
?- primeList(5,L).
L = [11, 7, 5, 3, 2].
But if I change the last line of the code from [P|L] to [L|P] like this:
primeListAcc(N,A,L,R) :-
N1 is N-1,
biggerPrime(A,P),
A1 is P+1,
primeListAcc(N1,A1,[L|P],R).
I get:
?- primeList(5,L).
L = [[[[[[]|2]|3]|5]|7]|11].
What am I missing? This is driving me mad!
Recall that a list is either the empty list [] or a term with functor '.' and two arguments, whose second argument is a list. The syntax [P|Ps] is shorthand notation for the term '.'(P, Ps), which is a list if Ps is a list (as is the case in your example). The term '.'(Ps, P), on the other hand, which can also be written as [Ps|P] (as you are doing), is not a list if P is not a list. You can obtain a reverse list with reverse/2.
Great, so you've discovered the problem of adding elements to the end of a list. In Prolog, we can do it with
add(X,L,Z):- L=[X|Z].
wait, what? How to read this? We must know the calling convention here. We expect L and Z to come in as uninstantiated variables, and we arrange for L from now on to point to a newly created cons node with X at its head, and Z its tail. Z to be instantiated, possibly, in some future call.
IOW what we create here is an open-ended list, L = [X|Z] = [X, ...]:
primeList(N,L) :-
primeListAcc(N,1,[],L).
primeListAcc(N,A,Z,L) :- N > 0, % make it explicitly mutually-exclusive,
N1 is N-1, % do not rely on red cuts which are easily
biggerPrime(A,P), % invalidated if clauses are re-arranged!
A1 is P+1,
L = [P|R], % make L be a new, open-ended node, holding P
primeListAcc(N1,A1,Z,R). % R, the tail of L, to be instantiated further
primeListAcc(0,A,R,R). % keep the predicate's clauses together
We can see now that Z is not really needed here, as it carries the [] down the chain of recursive calls, unchanged. So we can re-write primeListAcc without the Z argument, so that its final clause will be
primeListAcc(0,A,R):- R=[].
Keeping Z around as uninstantiated variable allows for it to be later instantiated possibly with a non-empty list as well (of course, only once (unless backtracking occurs)). This forms the basis of "difference list" technique.
To answer your literal question - here, consider this interaction transcript:
1 ?- X=[a|b].
X = [a|b]
2 ?- X=[a|b], Y=[X|c].
X = [a|b]
Y = [[a|b]|c]
the [a|b] output is just how a cons node gets printed, when its tail (here, b) is not a list. Atoms, as numbers, are not lists.

Resources