Add a no to each element of a list in prolog - prolog

i am new to Prolog. I am suppose to write Create a ternary predicate which will add the
first parameter, a number, to each number in the second parameter, a list. The third parameter will hold the result.
e.g.
?-addparam1(4,[a,3,6,b,8],X).
X=[a,7,10,b,12]
I wrote the following code:
test(X , [] ,[] ).
test(X , [H|T] ,[A|B]) :- add(X,H,A),test(X,T,B).
add(X,H,K):-K is H +X.
It works fine if I give only numbers in the list but not for alphabets. I tried using an if statement
add(X,H,K):- atom(H)->K is H ; K is H +X.
but still it didn't give the result.

You're almost right. is is the wrong operator, you'll want =. Also, it might be saver to check with number/1. Since [a] and a(b) also aren't atoms, but aren't numbers either.
This way it becomes:
add(X,H,K):-
number(H)->
K is H+X;
K = H.

Related

How to correct this 'Greater Than' Arithmetic Prolog code?

I am trying to write a simple prolog program where a number is compared with the elements in a list. To check that the number is greater than which elements in the list, and it simply returns the list with the elements that are less than the number. Example: gt(12,[19,4,6,22],L), this should return L = [4,6].
Here is my attempt:
gt(_,[],[]):-!.
gt(Num,[H|T],[H|L]):-
Num>H,
gt(Num,T,L).
gt(Num,[H|T],[H|L]):-
Num=<H,!,
gt(Num,T,L).
The problem that I am facing is in the =< predicate. If the condition is =< the number, then I am trying to say that ignore and move to the next number gt(Num,T,L). The place where I have written L, what should I write here so that it understands that I don't want you to write that value in the list?
Works alright for values that are already smaller than the number.
?-gt(12,[6,7,6],L).
L = [6,7,6]
But fail for such tests:
?- gt(12,[19,6,7],L).
L = [19, 6, 7]
The problem is in the third parameter in the third clause of gt/3. It is also "adding" the current item H as the head of the output list.
You should write
gt(Num,[H|T],L):-
Num=<H,!,
gt(Num,T,L).
instead.
You may also get rid of those cuts (!) to make your procedure work with other modes for the parameters and/or with uninstantiated variables.

Counting the number of lists in a nested list

I am having troubles counting the number of lists in a nested list.
count_lists([H|T],R):-
atomic(H),!,
count_lists(T,NR),
R is NR+1.
count_lists([[H|T]|Rest],R):-
!,
count_lists([H|T],R1),
count_lists(Rest,R2),
R is R1+R2.
count_lists([],0).
First of all, I try the basic case where an element in the list is atomic and thus, I should increment the counter by one. (Also, I tried removing the atomic predicate because I figured that because of it, my code will compute the number of elements in a nested list, but it still doesn't work)
Then, if the first element is a list itself, I go recursively on it and on the remaining list, adding the results.
And the third clause is states that the number of nested lists in an empty list is 0.
?count_lists([[1,5,2,4],[1,[4,2],[5]],[4,[7]],8,[11]],R).
should return 8 but instead, returns 12.
I know it's been a while since you asked this, but here is the answer I think you were looking for:
count_lists([],1).
count_lists([H|T],Rez):-atomic(H),!,count_lists(T,Part),Rez is Part.
count_lists([H|T],Rez):-count_lists(H,Part1),count_lists(T,Part2),Rez is Part1+Part2.
This way, you count only the number of lists and not the number of elements within.
you need to distinguish lists from other elements, i.e.
count_lists(E,R):-
is_list(E),!,count_elems(E,N),
R is N+1.
count_lists(_,0).
count_elems([H|T],R):-
count_lists(H,Hc),
count_elems(T,Tc),
R is Hc+Tc.
count_elems([],0).
but the code is contrived, using library we can get it done in 1 step:
count_lists(E, R):-
maplist(count_lists, E, Cs) -> sum_list(Cs, S), R is S+1 ; R = 0.
the code can be understood only WRT maplist/N behaviour
?- maplist(_,a).
false.
?- maplist(_,[]).
true.
?- maplist(_,[1]).
ERROR: apply:maplist_/2: Arguments are not sufficiently instantiated
In your solution you forget that e.g. [1,2,3] = [1,2,3| []] or [1,2,3] = [1| [2| [3| []]]]. Thus, you're "over-counting", thanks to your first clause. For example:
?- count_lists([1,2,3], N).
N = 3.
But there's another problem. In your second clause, if you've a nested list that nests other lists, you don't count it. Not clear from the title if that's intended or if it's a bug.
You shouldn't have complicated yourself.
count([],1).
count([L1|L2],Rez):- count(L1,Rez1),count(L2,Rez2),Rez is Rez1+Rez2.
You take out all the elements in a list recursively until you are left out with the empty list which values 1.

Categorise List in Prolog

Alright so I am coding a parser for arithmetic equations. I get the input in a list, e.g. "10+20" = [49,48,43,50,48] and then I convert all the digits to there corresponding numbers e.g. [49,48,43,50,48] = [1,0,43,2,0] and from there I want to put integers > 10 back together.
Converting from ascii -> digits I use a maplist and number_codes to convert.
One approach I had was to just traverse the list and if it's 0-9 store it in a variable and then check the next number, 0-9 append it to the other variable and so on until I hit an operator. I can't seem to simply append digits as it were. Here's my current code.
expression(L) :-
maplist(chars, L, Ls).
chars(C, N) :-
(
C >= "0", "9" >= C -> number_codes(N, [C]);
N is C
).
Not sure if there's a simple way to add to my code (as far as I know, maplist only gives back a list of equal length to the list passed in but I could be mistaken).
Any help is appreciated :)
Yes, maplist only 'gives back' a list of equal length. Moreover, maplist applies a predicate only to one element (basically it's context-free). Therefore, it is not possible to do what you want (combine digits between operators to a single number) with maplist and you would have to write the recursion yourself.
However, you can do something way easier than all this converting back and forth:
expression(L, E):-
string_to_atom(L,A),
atom_to_term(A,E,[]).
Which works like this:
2 ?- expression("1+2",E).
E = 1+2.
3 ?- expression("1+2",E), X is E.
E = 1+2, X = 3.
4 ?- expression("1+2",E), X+Y = E.
E = 1+2, X = 1, Y = 2.
5 ?- expression("1+2+3",E), X+Y = E.
E = 1+2+3, X = 1+2, Y = 3.
Naturally, if you want a list with all the numbers involved you will have to do something recursive but this is kinda trivial imho.
If however you still want to do the converting, I suggest checking Definite Clause Grammars; it will simplify the task a lot.
I answered some time ago with an expression parser.
It will show you how to use DCG for practical tasks, and I hope you will appreciate the generality and simplicity of such approach.
Just a library predicate is required from SWI-Prolog, number//1, easily implemented in Sicstus. Let me know if you need more help on that.

Sum of a list in prolog

I'm reading 'the art of prolog' book and I found an exercise that reads 'Define the relation sum(ListOfIntegers,Sum) which holds if Sum is the sum of the ListOfIntegers, without using any auxiliary predicate' .I came up with this solution:
sum([],Sum).
sum([0|Xs], Sum):-sum(Xs, Sum).
sum([s(X)|Xs], Sum):-sum([X|Xs],s(Sum)).
Which does not work exactly as I would want it to.
?- sum([s(s(0)),s(0),s(s(s(0)))],X).
true ;
false.
I was expecting X to be
s(s(s(s(s(s(0))))))
I thought that the problem is that I have to 'initialize' Sum to 0 in the first 'iteration' but that would be very procedural and unfortunately I'm not quite apt in prolog to make that work.
Any ideas or suggestions?
Your first clause should read
sum([], 0).
With that change, the vacuous true return goes away and you're left with one problem: the third clause reverses the logic of summation. It should be
sum([s(X)|Xs], s(Sum)) :- sum([X|Xs], Sum).
because the number of s/1 terms in the left argument to sum/2 should be equal to the number of them in the right argument.
The best way to localize the problem is to first simplify your query:
?- sum([0],S).
true.
?- sum([],S).
true.
Even for those, you get as an answer that any S will do. Like
?- sum([],s(s(0))).
true.
Since [] can only be handled by your fact, an error must lie in that very fact.
You stated:
sum([], Sum).
Which means that the sum of [] is just anything. You probably meant 0.
Another error hides in the last rule... After fixing the first error, we get
?- sum([0],Sum).
Sum = 0.
?- sum([s(0)],Sum).
false.
Here, the last clause is responsible. It reads:
sum([s(X)|Xs], Sum):-sum([X|Xs],s(Sum)).
Recursive rules are relatively tricky to read in Prolog. The simplest way to understand them is to look at the :- and realize that this should be an arrow ← (thus a right-to-left arrow) meaning:
provided, that the goals on the right-hand side are truewe conclude what is found on the left-hand side
So, compared to informal writing, the arrows points into the opposite direction!
For our query, we can consider the following instantiation substituting Xs with [] and X with 0.
sum([s(0)| [] ], Sum) :- sum([0| []],s(Sum)).
So this rule now reads right-to-left: Provided, sum([0],s(Sum)) is true, ... However, we do know that only sum([0],0) holds, but not that goal. Therefore, this rule never applies! What you intended was rather the opposite:
sum([s(X)|Xs], s(Sum)):-sum([X|Xs],Sum).
I'm not really following your logic, what with all the seemingle extraneous s(X) structures floating about.
Wouldn't it be easier and simpler to do something like this?
First, define your solution in plain english, thus:
The sum of an empty list is 0.
The sum of a non-empty list is obtained by adding the head of the list to the sum of the tail of the list.
From that definition, the prolog follows directly:
sum( [] , 0 ) . % the sum of an empty list is 0.
sum( [X|Xs] , T ) :- % the sum of an non-empty list is obtained by:
sum( Xs , T1 ) , % - first computing the sum of the tail
T is X + T1 % - and then, adding that the to head of the list
. % Easy!

Prolog - How this program work

I have this program written in prolog language.
The problem is that i cant understand how it works.
even_number([],[]).
even_number([H|T],S):-even_number(T,W),Z is H mod 2,Z==0,S=[H|W].
even_number([_|T],S):-even_number(T,S).
All it does is to extract the even numbers from a list and store it to another list.
I know that it works using recursion but i cant understand the steps that are made during execution.
Can anyone explain?
The program consists of three rules that are applied as a group. They work together basically as if ... else if ... else if ... [else fail].
The first rule is: the even numbers in an empty list is the empty list. This is easy enough.
The second rule is applied if the first rule fails (i.e., the first argument isn't the empty list). This is a bit more complicated, but basically says to include the first element of the list if it is even. The logic breaks down as follows. The even numbers in a list that starts with H and has a tail of T is S if all the terms on the right are true: that the even numbers in T is some list W; that Z is the remainder after dividing H by 2; that Z is zero; and that S is H followed by W (whatever W turned out to be). (Note that this rule would be more efficient if the first term was moved to after the test Z==0.)
If that rule fails (i.e., H is odd), then the last rule is applied: the even numbers in the list are the even numbers in the tail of the list.
It's written rather poorly. It might be easier to understand if you refactor it a bit and make it tail recursive:
even_numbers( X , R ) :-
even_numbers( X , [] , T ) ,
reverse( T , R ).
even_numbers( [] , T , T ).
even_numbers( [X|Xs] , T , R ) :-
Z is X mod 2 ,
Z == 0 ,
! ,
even_numbers( Xs , [X|T] , R ).
even_numbers( [_|Xs] , T , R ) :-
even_numbers( Xs , T , R ).
The first predicate, even_numbers/2 predicate is the public wrapper. It invokes the private helper, even_numbers/3, which hands back the list of even numbers in reverse order. It reverses that and tries to unify it with the result passed in the wrapper.
The helper method does this:
if the source list is empty: unify the accumulator (T) with the result.
if the source list is not empty, and the head of the list (X) is even,
recurse down on the tail of the list (Xs), pushing X onto the accumulator.
if the source list is not empty, and the head of the list (X) is odd,
recurse down on the tail of the list (Xs) without modifying the accumulator.
But as noted by #André Paramés, work through it in the debugger and it will become clear what's going on.

Resources