Problems with Tail Recursion and reversing list? - recursion

Hello I have a call like this list of digits(436,L).
How can I reverse the list, and make it tail recursive??
list_of_digits(0,[]).
list_of_digits(M, [Z|Zx]) :- M > 0 ,
MM is floor(M / 10),
Z is M mod 10,
list_of_digits(MM,Zx).
Can anyone help me please??
I want to transform my number, in this case 436 into
a List like [4,3,6].
I call ?- list_of_digits(436,L)
and get
L = [6,3,4] ;
false.
back.

Using an accumulator:
list_of_digits(X,L) :- lod_acc(X, [], L).
lod_acc(0,R,R).
lod_acc(M,Acc,R) :-
M > 0,
MM is floor(M / 10),
Z is M mod 10,
lod_acc(MM,[Z|Acc],R).

I'd do it this way, to deal with negative numbers and with zero itself (a special case):
%
% the external/public API predicate.
%
% this handles the special case of zero, which has 1 digit.
% all other cases are handled by the internal worker predicate.
%
digits_in( X , Ds ) :- int(X) , X > 0 , digits_in(X,[],Ds).
digits_in( X , Ds ) :- int(X) , X < 0 , Y is abs(X) , digits_in(Y,[],Ds).
digits_in( 0 , [0] ) .
%
% the internal/private guts-of-the-operation predicate
%
digits_in( 0 , Ds , Ds ). % when we hit zero, we're done.
digits_in( X , Ts , Ds ) :- % otherwise...
T is X mod 10 , % get the lower order digit via modulus arithmetic
X1 is X // 10 , % get the high order digits via integer division
digits_in( X1 , [T|Ts] , Ds ) % [tail-]recurse down.
.

Related

What is causing an infinite recursion? (Prolog)

I'm trying to approach a problem in which given M and N integers, returns in res a list with the powers of M that are less than or equal to N, in descending order.
example: powers(3,9,res).
res = [9,3,1]
My approach is as follows:
power(X,0,1).
power(X,Y,Z) :- X>0,
Yminus1 is Y - 1,
power(X,Yminus1,Z1),
Z is X*Z1.
increment(X,newX) :- newX is X + 1.
powers(M,N,res) :- integer(M), integer(N),
powersAux(M,N,0,res).
powersAux(M,N,E,res) :- power(M,E,Z),
Z=<N,
increment(E,E1),
res1 = [Z|res],
powersAux(M,N,E1,res1).
I'm getting my memory stack filled so I understand that the recursion never ends.
You need to handle special cases:
0n is always 0
1n is always 1
And Prolog has an in-built exponiation function: **/2.
A common Prolog idiom is to have a public predicate that does little outside of constraint validation, that invokes an "internal" helper predicate that does the work. The helper predicate often takes additional parameters that maintain state needed for computation.
That leads to this:
powers( X , L, Ps ) :-
non_negative_integer(X),
non_negative_integer(L),
powers(X,0,L,[],Ps)
.
non_negative_integer(X) :- integer(X), X >= 0 .
% ---------------------------------------------------------------
%
% powers( +Base, +Exponent, +Limit, +Accumulator, ?Results )
%
% where Base and Radix are guaranteed to be non-negative integers
% ---------------------------------------------------------------
powers( 0 , _ , _ , _ , [0] ) :- ! . % 0^n is always 0
powers( 1 , _ , 0 , _ , [] ) :- ! . % 1^n is always 1
powers( 1 , _ , L , _ , [1] ) :- L >= 1 , !. % 1^n is always 1
powers( X , Y , L , Ps , Ps ) :- X**Y > L , !. % when x^y exceeds the limit, we're done, and
powers( X , Y , L , Ts , Ps ) :- % otherrwise...
T is X**Y , % - compute T as x^y
Y1 is Y+1, % - increment Y
powers(X,Y1,L,[T|Ts],Ps) % - recurse down, prepending T to the accumulator list.
. % Easy!
Which gives us
?- powers(2,1024,Ps).
Ps = [1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1]

Prolog predicate without using lists

I am required to write a prolog predicate count(X,Y,D,N) without using lists that should count the number of elements between two integers X and Y inclusive. However, it should only count those values that are divisible by D.
For example, count(3,6,2,N) should return N = 2 because 4 and 6 are divisible by 2, but 3 and 5 are not.
Recursion is your friend here (as is the case with most things Prolog).
A helper predicate that takes an additional parameter that acts as an accumulator is useful here:
Something like this should do you:
count( X, Y, D, N ) :- count( X, Y, D, 0, N ) .
count( X , Y , D , T , N ) :- X =< Y, % If X <= Y ...
( X rem D =:= 0 % - and X is divisible by D
-> T1 is T+1 % - then increment T
; T1 = T % - otherwise don't
), % and
X1 is X+1, % - increment X
count( X1, Y, D, T1, N ). % - recurse down
count( X , Y , _ , N , N ) :- X > Y. % IF X > Y, we're done: unify the accumulator with the result.
The above is tail-recursive and is for all intents and purposes optimized into iteration. The more classic recursive solution is something like this:
count( X, Y, _, 0 ) :- X > Y .
count( X, Y, D, N ) :- X =< Y ,
X1 is X+1,
count( X1, Y, D, T ),
( 0 =:= X rem D -> N is T+1 ; N = T )
.

Stop recursion when variable is reached

I have a prolog program with searches for something and every time it hasn't found it, it increments a variable by 1. If it never finds what the user is searching for, it will search forever. Can I stop prolog from doing that, if a special variable is reached? This is the predicate which searches for something:
% ---------------------------------------------------------------------
% find(X,Y,N) :- ...search for it
% find(X,Y,N) :- ...if not found, increment N by 1 and repeat recursion
% ---------------------------------------------------------------------
find(Y,I,G) :- member(Y,I), G is 0.
find(Y,I,G) :- not(member(Y,I)), expand(I,O), find(Y,O,G1), G is G1+1.
find(Y,I,50) :- fail.
So I want to write something like
find(X,Y,50) :- return false
So that the program returns false, if it hasn't found it after 50 recursions.
How do I realize that?
EDIT: This is my code: http://pastebin.com/4X7BSFQ2
vwg(X,Y,G) is searching if the two persons X and Y are related with grade G
for example:
vwg(vanessaMueller, selinaMueller, 1)
is true, cause vanessaMueller is her mother
If you always have the third argument (the iteration count) bound, you can simply count down. Once you hit zero, you've failed:
find( Y , I , G ) :- %
integer(G) , % enforce the contract that G must be bound
G > 0 , % if we've not yet hit zero,
member(Y,I) , % see if we can find Y in I
! . % and eliminate any alternatives.
find( Y , I , G ) :- %
integer(G) , % enforce the contract that G must be bound
G > 0 , % if we've not yet hit zero
G1 is G-1 , % decrement G
expand(I,I1) , % expand I
find(Y,I1,G1) % and recurse down
. %
Note that the above requires the initial call to to find/3 to have its third argument bound to an integer.
If, instead, you want your third argument to return the count, rather than defining a limit (and using a hard-coded limit instead), you can use a helper with an accumulator:
find( Y , I, G ) :-
find(Y,I,1,G)
.
find( Y , I , G , G ) :-
G =< 50 , % if we've not yet exceeded the limit
member(Y,I) , % see if we can find Y in I
! . % and eliminate alternatives
find( Y , I , T , G ) :- %
T < 50 , % if we're below the limit
T1 is T+1 , % increment the accumulator
expand(I,I1) , % expand I
find(Y,I1,T1,G) % and recurse down.
. % easy!
Or you can pass in the limit another argument and get the recursion count on success:
find( Y , I, N , G ) :-
find(Y,I,N,1,G)
.
find( Y , I , N , G , G ) :-
G =< N ,
member(Y,I) ,
! .
find( Y , I , N , T , G ) :-
T < N ,
T1 is T+1 ,
expand(I,I1) ,
find(Y,I1,N,T1,G)
.
There's more than one way to do it.
from your pastebin, I get
find(Y,I,G) :- member(Y,I), G is 0.
find(Y,I,G) :- not(member(Y,I)), expand(I,O), find(Y,O,G1), G is G1+1.
find(Y,I,50) :- fail.
I would try
find(Y,I,0) :- member(Y,I).
find(Y,I,G) :- G < 50, not(member(Y,I)), expand(I,O), G1 is G+1, find(Y,O,G1).
Depending on your interpreter you can use
find(X,Y,50) :- fail

Translating Roman numerals into Arabic ones

I have built a predicate, which converts Roman numerals into Arabic ones. The only problem is that the predicate is limited: if I want to convert more than 3 Arabic numerals at once it does not work anymore.
This is how the predicate should work:
?- convert([v,i,i],Arabic).
Arabic = 7.
My solution so far:
tran([],0).
tran(i,1).
tran(v,5).
tran(x,10).
convert([],X) :- X is 0, !.
convert([T],X) :- tran(T,E), X is E,!.
convert([T|Ts],X) :- tran(T,E), tran(Ts,Es), X is E+Es,!.
convert([T,Ts,Tss],X) :- tran(T,E), tran(Ts,Es), tran(Tss,Ess), X is E+Es+Ess.
I know why the predicate does not work with more than 3 numerals and I could also expand the convert-predicate, but with the same pattern as shown above.
How can I make the convert-predicate more "general" (so that it could work independently of the number of numerals)? Or do you have other ideas how to write the predicate?
Thanks :)
I haven't tested this too much, but I've tried it on several numbers and it seems to work.
The code obeys "subtractive pair rule", described, for example, at https://projecteuler.net/about=roman_numerals
The code uses "accumulator" technique to pass information what was the sum of digits seen before. Initial call just sets the accumulator to 0.
digit(i, 1).
digit(v, 5).
digit(x, 10).
digit(l, 50).
digit(c, 100).
digit(d, 500).
digit(m, 1000).
convert(Roman, Arabic) :-
convert(Roman, 0, Arabic).
convert([], Acc, Acc).
convert([A], Acc, Arabic) :-
digit(A, AVal),
Arabic is Acc + AVal.
convert([A, B | Rest], Acc, Arabic) :-
digit(A, AVal), digit(B, BVal),
AVal < BVal,
NewAcc is Acc + BVal - AVal,
convert(Rest, NewAcc, Arabic).
convert([A, B | Rest], Acc, Arabic) :-
digit(A, AVal), digit(B, BVal),
AVal >= BVal,
NewAcc is Acc + AVal,
convert([B | Rest], NewAcc, Arabic).
Some tests:
convert([v, i, i], Arabic).
Arabic = 7
?- convert([x, i, x], Arabic).
Arabic = 19
?- convert([m, d, c, v, i], Arabic).
Arabic = 1606
It's probably possible to write a predicate convert that works both ways in true Prolog spirit using constraint programming, but I haven't tried this approach.
It might help if you consider the number of discrete "digits" in the Roman numbering system is more than just I, X and V, viz:
roman( "M" , 1000 ) .
roman( "CM" , 900 ) .
roman( "D" , 500 ) .
roman( "CD" , 400 ) .
roman( "C" , 100 ) .
roman( "XC" , 90 ) .
roman( "L" , 50 ) .
roman( "XL" , 40 ) .
roman( "X" , 10 ) .
roman( "IX" , 9 ) .
roman( "V" , 5 ) .
roman( "IV" , 4 ) .
roman( "I" , 1 ) .
Then you can write something like
roman_to_decimal( R , D ) :-
roman_to_decimal( R , 0 , D )
.
roman_to_decimal( [] , D , D ) :- .
roman_to_decimal( R , T , D ) :-
roman(P,V) ,
append(P,S,R) ,
! ,
T1 is T+V ,
roman_to_decimal(S,T1,D)
.
Invoke it as
roman_to_decimal( "MCM" , D ) .
This does have some shortcomings, to whit:
It doesn't enforce syntax: the Roman numbering system required the discrete components to be ordered left-to-right in descending order of value. This doesn't take that into consideration.
It doesn't take into account the many variations. Should 999 be represented as the compact IM or as the rather more verborse CMXCIX?
Just to add a variant to the mix, this version uses the scheme in Sergey's answer (which also allows more arbitrary subtractive sequences), and allows a more human-readable input like Nicholas' answer.
numeral('I', 1).
numeral('V', 5).
numeral('X', 10).
numeral('L', 50).
numeral('C', 100).
numeral('D', 100).
numeral('M', 1000).
r2n(R, N) :-
char_code(A, R),
lower_upper(A, C),
numeral(C, N).
trans(R, N) :-
maplist(r2n, R, Rn), % Pre-calculate a numeric list representation
trans(Rn, 0, N).
trans([X,Y|T], Acc, N) :-
X >= Y,
Acc1 is Acc + X,
trans([Y|T], Acc1, N).
trans([X,Y|T], Acc, N) :-
X < Y,
Acc1 is Acc - X,
trans([Y|T], Acc1, N).
trans([X], Acc, N) :-
N is Acc + X.
trans([], N, N). % Optional rule: needed only if you want trans("", 0). to succeed
Note these rules will allow any valid Roman numeral, but will also do something with and succeed on some improperly formed Roman numerals. So it is not a set of rules to validate proper Roman numerals.
Sample output:
| ?- trans("mmxiv", X).
X = 2014 ? ;
no
| ?- trans("CMXCIX", X).
X = 999 ? ;
no
| ?- trans("IM", X).
X = 999 ? ;
no
| ?- trans("IVX", X). % Not a properly-formed Roman numeral
X = 4 ? ; % Uh... ok... I guess
no

Prolog program to convert(L,X) that converts list L to an integer: x1 + x2*10^1+ … + xn*10^(n-1)

My Problem: Given a list
L = [x1,...,xn]
write a Prolog program convert(L,X) that converts L to an integer
x1*10^0 + x2*10^1 + ... + xn*10^(n-1)
storing the the result in X.
For example
?- convert( [1,2,3,4] , Res ).
Res = 4321.
I was trying to solve this problem, but I'm getting syntax error where i'm trying to use built-in function of power. This is what I have so far:
convert([],Res) .
convert(L1,Res) :- conv( L1 , Res , C ) .
conv( [] , Res , C ) .
conv( [H|Ys] , Res , C ):-
C1 is C-1 ,
N is (H*(10**C)) ,
conv(Ys,Res2,C1) ,
Res is N + Res2 .
I get this error:
******* syntax error
>>> conv ( [ H | Ys ] , Res , C ) :- C1 is C - 1 , N is ( H * ( 10 <--- HERE? >>>
So somebody can tell me how to get rid of this error??
Plus is there any way I'm going wrong syntactically??
Please help me with this. Thank you.
As you use SWI-Prolog, this works :
:- use_module(library(lambda)).
convert(L,Res) :-
reverse(L, LR),
foldl(\X^Y^Z^(Z is Y * 10 + X), LR, 0, Res).
For your code :
convert([],Res) . <== Here Res is a free variable
convert(L1,Res) :-conv(L1,Res,C). <== here C is free
conv([],Res,C). <== Here Res anc C are free
This can't work; You can try
conv([],0).
conv([H|Ys],Res):-
conv(Ys,Res2),
Res is Res2 * 10 + H.
The original poster was on the right track. This will do, though, without using library(lambda):
convert( Xs , R ) :- % to sum a list of values, scaling each by their corresponding power of 10,
convert( Xs , 1 , 0 , R ) % just invoke the worker predicate, seeding the power accumulator with 10^0 (1)
. % and the result accumulator with zero (0).
convert( [] , _ , R , R ) . % when we exhaust the source list, we're done: unify the result R with the result accumulator
convert( [X|Xs] , P , T , R ) :- % otherwise...
T1 is T + X*P , % - increment the result accumulator by the current list item, scaled by the current power of 10,
P1 is P*10 , % - bump up to the next power of 10, and
convert(Xs,P1,T1,R) % - recurse down.
. %
It can also be done using Prolog's built-in exponentiation (but it's neither simpler, nor faster):
convert( Xs , R ) :-
convert(Xs,0,0,R)
.
convert( [] , _ , R , R ) .
convert( [X|Xs] , N , T , R ) :-
T1 is T + X * 10**N ,
N1 is N+1 ,
convert1(Xs,N1,T1,R)
.
The easiest and most elegant way, though (at least in SWI, Quintus or Sicstus) would be to use library(aggregate) and write the one-liner:
convert( Xs , R ) :- aggregate( sum(X*10**N) , nth0(N,Xs,X) , R ) .

Resources