I'm quite new in prolog and I want to practice rewriting a tail-recursion code into a simple recursion to understand better the process, but I did not succeed in it. If anybody can help with it I would really appreciate it.
Note: Converting tail-recursive (tail-call) code to non tail-recursive code is not a wise thing to normally do in Prolog. This question is only for academic purposes of learning.
The code:
some_predicate(T,1,3,0,D),
%the tail has elements with ID and Numbers like [(1,3),(2,5),(4,3)])
%in the D I count steps if different conditions are fulfilled
%I would like to write something like: some_predicate(T,1,3,D) without the Acc
some_predicate(_, _, 1, D, D):-!.
some_predicate([], _, _, D, D):-!.
some_predicate([(UP,_)|_], ID, H, D, D):-
UP >= ID + H,
!.
some_predicate([(UP,UH)|T], _, H, D, RetD):-
H > UH,
TH is H - 1,
TD is D + 1,
some_predicate(T, UP, TH, TD, RetD),
!.
some_predicate([(UP,UH)|T], _, _,D, RetD):-
TD is D + 1,
some_predicate(T, UP, UH, TD, RetD),
!.
My attempt
some_predicate(_, _, 1,0):-!.
some_predicate([], _, _,0):-!.
some_predicate([(UP,_)|_], ID, H, 0):-
UP >= ID + H,
!.
some_predicate([(UP,UH)|Er], _, H, D):-
H > UH,
some_predicate(Er, UP, TH, TD),
H is TH - 1,
D is TD + 1,
!.
some_predicate([(UP,UH)|Er], _, _,D):-
some_predicate(Er, UP, UH, TD),
D is TD + 1,
!.
A comment in the question says that you would like to rewrite the code without an accumulator, but it doesn't use an accumulator. The general schema for predicates using a list accumulator would be something like this:
foo(X, Ys) :-
foo(X, [], Ys).
foo(X, Acc, Acc) :-
bar(X).
foo(X, Acc, Ys) :-
baz(X, Y, Z),
foo(Z, [Y | Acc], Ys).
The recursive call involving the list accumulator gets a bigger list than the accumulator was before. You add something to the accumulator before you pass it to the recursive call.
Your program instead uses the common pattern of "list iteration" (comments with a better name are welcome) in Prolog which does the opposite of recursion using an accumulator:
foo([], Y) :-
bar(Y).
foo([X | Xs], Y) :-
baz(X),
foo(Xs, Y).
(This uses similar names to the predicate before, but I'm not saying that they are equivalent.)
The list constructor [_ | _] is in the head of the clause, not in a recursive call. The list in the recursive call is smaller than the list in the head. You remove something from the list before you pass the tail to the recursive call.
This is therefore not an answer your question, just a hint that you need to start from the right place: Some predicate definition that really does use an accumulator list. The simplest interesting case is probably reversing a list.
Related
I am brand new to prolog and I feel like there is a concept that I am failing to understand, which is preventing me from grasping the concept of recursion in prolog. I am trying to return S, which is the sum of the square of each digit, taken as a list from an integer that is entered by the user in a query. E.g The user enters 12345, I must return S = (1^2)+(2^2)+(3^2)+(4^2)+(5^2) = 55.
In my program below, I understand why the each segment of the calculation of S is printed multiple time as it is part of the recursive rule. However, I do not understand how I would be able to print S as the final result. I figured that I could set a variable = to the result from sos in the second rule and add it as a parameter for intToList but can't seem to figure this one out. The compiler warns that S is a singleton variable in the intToList rule.
sos([],0).
sos([H|T],S) :-
sos(T, S1),
S is (S1 + (H * H)),
write('S is: '),write(S),nl.
intToList(0,[]).
intToList(N,[H|T]) :-
N1 is floor(N/10),
H is N mod 10,
intToList(N1,T),
sos([H|T],S).
The issue with your original code is that you're trying to handle your call to sos/2 within your recursive clause for intToList/2. Break it out (and rename intToList/2 to something more meaningful):
sosDigits(Number, SoS) :-
number_digits(Number, Digits),
sos(Digits, SoS).
Here's your original sos/2 without the write, which seems to work fine:
sos([], 0).
sos([H|T], S) :-
sos(T, S1),
S is (S1 + (H * H)).
Or better, use an accumulator for tail recursion:
sos(Numbers, SoS) :-
sos(Numbers, 0, SoS).
sos([], SoS, SoS).
sos([X|Xs], A, SoS) :-
A1 is A + X*X,
sos(Xs, A1, SoS).
You can also implement sos/2 using maplist/3 and sumlist/2:
square(X, S) :- S is X * X.
sos(Numbers, SoS) :- maplist(square, Numbers, Squares), sumlist(Squares, SoS).
Your intToList/2 needs to be refactored using an accumulator to maintain correct digit order and to get rid of the call to sos/2. Renamed as explained above:
number_digits(Number, Digits) :-
number_digits(Number, [], Digits).
number_digits(Number, DigitsSoFar, [Number | DigitsSoFar]) :-
Number < 10.
number_digits(Number, DigitsSoFar, Digits) :-
Number >= 10,
NumberPrefix is Number div 10,
ThisDigit is Number mod 10,
number_digits(NumberPrefix, [ThisDigit | DigitsSoFar], Digits).
The above number_digits/2 also handles 0 correctly, so that number_digits(0, Digits) yields Digit = [0] rather than Digits = [].
You can rewrite the above implementation of number_digits/3 using the -> ; construct:
number_digits(Number, DigitsSoFar, Digits) :-
( Number < 10
-> Digits = [Number | DigitsSoFar]
; NumberPrefix is Number div 10,
ThisDigit is Number mod 10,
number_digits(NumberPrefix, [ThisDigit | DigitsSoFar], Digits)
).
Then it won't leave a choice point.
Try this:
sos([],Accumulator,Accumulator).
sos([H|T],Accumulator,Result_out) :-
Square is H * H,
Accumulator1 is Accumulator + Square,
sos(T,Accumulator1,Result_out).
int_to_list(N,R) :-
atom_chars(N,Digit_Chars),
int_to_list1(Digit_Chars,Digits),
sos(Digits,0,R).
int_to_list1([],[]).
int_to_list1([Digit_Char|Digit_Chars],[Digit|Digits]) :-
atom_number(Digit_Char,Digit),
int_to_list1(Digit_Chars,Digits).
For int_to_list I used atom_chars which is built-in e.g.
?- atom_chars(12345,R).
R = ['1', '2', '3', '4', '5'].
And then used a typical loop to convert each character to a number using atom_number e.g.
?- atom_number('2',R).
R = 2.
For sos I used an accumulator to accumulate the answer, and then once the list was empty moved the value in the accumulator to the result with
sos([],Accumulator,Accumulator).
Notice that there are to different variables for the accumulator e.g.
Accumulator1 is Accumulator + Square,
sos(T,Accumulator1,Result_out).
this is because in Prolog variables are immutable, so one can not keep assigning new values to the same variable.
Here are some example runs
?- int_to_list(1234,R).
R = 30.
?- int_to_list(12345,R).
R = 55.
?- int_to_list(123456,R).
R = 91.
If you have any questions just ask in the comments under this answer.
I'm writing a prolog predicate which replace an element with another in a given atom. The predicate I wrote is like this:
replace_var(Expr0, Var, Val, Expr) :-
Expr0 =.. Chars,
chars_replaced(Chars, Rs),
Expr =.. Rs.
chars_replaced(Chars, Rs) :-
maplist(rep, Chars, Rs).
rep(Var,Val).
rep(C, C) :- dif(C,var).
The result I want it to return is something like:
-?replace_var(hello, l, w, X).
X = hewwo.
The problem is about the rep() predicate. I don't know how to write it or how to pass the Val and Var to the predicate.
Please give me some suggestions. Thanks!
this is wrong
Expr0 =.. Chars
you need instead
atom_chars(Expr0, Chars)
and this one really puzzle me
rep(Var,Val).
rep(C, C) :- dif(C,var).
what do you mean, specially the second one ?
anyway, the whole could be
replace_var(Expr0, Var, Val, Expr) :-
atom_chars(Expr0, Cs),
maplist(rep(Var, Val), Cs, Ts),
atom_chars(Expr, Ts).
rep(C, T, C, T).
rep(_, _, C, C).
disclaimer: untested code
I am working through the Purescript By Example tutorial and I am having trouble getting types to line up using a fold left as such:
smallestFile' :: [Path] -> Maybe Path
smallestFile' (x : xs) = foldl(\acc i -> smallerFile(acc i) ) Just(x) xs // Error is on this line
smallerFile :: Maybe Path -> Path -> Maybe Path
smallerFile maybeA b = do
a <- maybeA
sa <- size a
sb <- size b
if sa > sb then return(b) else return(a)
The error I am receiving is on the fold left and is
Cannot unify Prim.Function u13116 with Data.Maybe.Maybe
I believe that the types line up, but I cannot make heads or tails of this error.
Also, is it possible to clean up the anonymous function syntax so that
foldl(\acc i -> smallerFile(acc i) ) Just(x) xs
becomes something like:
foldl smallerFile Just(x) xs
In PureScript, like Haskell, function application uses whitespace, and associates to the left, which means that f x y z parses as ((f x) y) z. You only need parentheses when terms need to be regrouped. It looks like you're trying to use parentheses for function application.
I suspect what you want to write is
foldl (\acc i -> smallerFile acc i) (Just x) xs
The argument to foldl is a function which takes two arguments acc and i and returns the application smallerFile acc i. This is equivalent to the double application (smallerFile acc) i. First we apply the argument acc, then the second argument i. The precedence rule for function application in the parser makes these equivalent.
Also, Just x needs to be parenthesized because what you wrote parses as
foldl (\acc i -> smallerFile (acc i)) Just x xs
which provides too many arguments to foldl.
Once you have the correct version, you can notice that \acc i -> smallerFile acc i is equivalent to \acc -> (\i -> (smallerFile acc) i). The inner function applies its argument i immediately, so we can simplify this to \acc -> smallerFile acc. Applying this simplification a second time, we get just smallerFile, so the code becomes:
foldl smallerFile (Just x) xs
so the only mistake in the end was the incorrect bracketing of Just x.
I'm new in Prolog and I have some problem understanding how the recursion works.
The think I want to do is to create a list of numbers (to later draw a graphic).
So I have this code :
nbClassTest(0, _).
nbClassTest(X, L) :-
numberTestClass(A,X),
append([A], L, L),
X is X - 1,
nbClassTest(X, L).
But it keeps giving me 'false' as an answer and I don't understand why it doesn't fill the list. It should end if X reaches 0 right?
The numberTestClass(A,X), gives me a number (in the variable A) for some X as if it was a function.
You should build the list without appending, because it's rather inefficient.
This code could do:
nbClassTest(0, []).
nbClassTest(X, [A|R]) :-
numberTestClass(A, X),
X is X - 1,
nbClassTest(X, R).
or, if your system has between/3, you can use an 'all solutions' idiom:
nbClassTest(X, L) :-
findall(A, (between(1, X, N), numberTestClass(A, X)), R),
reverse(R, L).
the problem is that you use the same variable for the old and the new list. right now your first to append/3 creates a list of infinite length consisting of elements equal to the value of A.
?-append([42],L,L).
L = [42|L].
?- append([42],L,L), [A,B,C,D|E]=L.
L = [42|L],
A = B, B = C, C = D, D = 42,
E = [42|L].
then, if the next A is not the same with the previous A it will fail.
?- append([42],L,L), append([41],L,L).
false.
there is still on more issue with the code; your base case has an non-instantiated variable. you might want that but i believe that you actually want an empty list:
nbClassTest(0, []).
nbClassTest(X, L) :-
numberTestClass(A,X),
append([A], L, NL),
X is X - 1,
nbClassTest(X, NL).
last, append/3 is kinda inefficient so you might want to avoid it and build the list the other way around (or use difference lists)
It fails because you use append in wrong way
try
nbClassTest(0, _).
nbClassTest(X, L) :-
numberTestClass(A,X),
append([A], L, Nl),
X is X - 1,
nbClassTest(X, Nl).
append concatenate 2 lists so there is no such list which after adding to it element still will be same list.
I'm trying to write a meta-interpreter in prolog for prolog, which would return maximal reached recursion depth in a given prolog program.
This code actually counts number of all recursive calls in a program:
rc( true, 0) :- !.
rc( ( Goal1, Goal2), N) :- !, %we have multiple goals
rc( Goal1, N1), %count recursive calls in Goal1
rc( Goal2, N2), %count recursive calls in goals Goal2
N is N1 + N2. %add both counters
rc( Goal, N) :-
clause( Goal, Body),
functor( Goal, F, A), %get functor and airity
rcount( F/A, Body, NF), %count calls of that functor/airity in the body
rc( Body, NB), %recursively process the body
N is NF + NB. %add counters
I must somehow keep track of each individual recursion path and compare their depths, but have problems defining this in prolog. Can somebody point me into the right direction?
Thanks.
You can try something along these lines:
solve(true, 0) :- !.
solve(Head, Hdepth) :- clause(Head, Body), solve(Body, Bdepth),
Hdepth is Bdepth + 1.
solve((Goal1, Goal2), Depth) :- solve(Goal1, Depth1), solve(Goal2, Depth2),
Depth is max(Depth1, Depth2).