Can someone explain how this code works. I am new to Prolog and I am having trouble thinking like a Prolog programmer.
When you input a number followed by a comma and any variable name, it gives you the sum up to that number
sum_to(1,1) :- !.
sum_to(N, R) :- N1 is N-1, sum_to(N1,TR), R is TR + N.
So sum_to(4, N) gives N = 10.
Your definition can be equivalently written as
sum_to( N, R) :- N = 1, R = 1, !.
sum_to( N, R) :- N1 is N-1, sum_to( N1, R1), R is R1+N.
This is a recursive definition -- it contains a call to the same predicate as the predicate itself. Under the condition that you're going to always call it with a free variable as the second argument and a concrete (hopefully positive) number as the first argument, it expresses a function which calculates the second argument's value from the given first argument.
Thus what you have is a recursive functional definition.
Now let's work through some examples, from the simplest to the progressively more and more complex:
sum_to( 1, R1) :- 1 = 1, R1 = 1, !.
\______________/
R1 = 1.
sum_to( 2, R2) :- N1 is 2-1, sum_to( N1, R1), R2 is R1+2.
\________/
N1 is 1, sum_to( 1, R1),
\____________/
R1 = 1, R2 is 1+2
\_____________________________________/
R2 = 3.
sum_to( 3, R3) :- N2 is 3-1, sum_to( N2, R2), R3 is R2+3.
\________/
N2 is 2, sum_to( 2, R2),
\____......____/
\__________________/
R2 = 3, R3 is 3+3
\_____________________________________________/
R3 = 6.
Right? As the execution progresses through the goals left to right, our variables take on their concrete values one after the other, thus enabling the execution of the next goal, and the next, which instantiate yet more variables, until the final value becomes known.
Now do sum_to( 4, R4).
This is a very imperative-style program implementing an inductive definition concidentally written in Prolog.
It relates two numbers:
In the first clause 1 is related to 1. The ! indicates that the interpreter should stop looking for further solutions in the sum_to/2 predicate.
If the first clause doesn't match (because any of the arguments in the call was different from 1) then the second clause is examined.
And now we simply:
Compute N1 as N-1
Make a recursive call with N1, and getting a value in TR such that N1 and TR are related via sum_to/2 (i.e. TR should be the sum of all integers up to N1). Once we get that, we compute R as the sum of TR and N.
The sum_to relation is correct for the first argument being 1.
The sum_to relation at N is correct if the sum_to relation is correct for N-1.
Computation will terminate if the recursive call "makes something smaller" on each call and will eventually hit a smallest value. It does indeed make N smaller on each call and will eventually hit 1. (Unless one calls this predicate with a 0 N or smaller. Then: catastrophe!)
Looking good.
(Incidentally, inductive definitions tend to go from a constant x to +oo, i.e. "going upwards"; above I am stating correctness moving from any N down towards 1. Am I justified in doing so?)
Related
The scenario is to mimic rolling 3 six-sided die in Prolog while trying to obey the recursive nature of prolog. This is easily done with the Fibonacci series
n_factorial(N, F) :-
N #> 0,
F #= N*F1,
N1 #= N-1,
n_factorial(N1, F1).
I'm having difficulty translating this to the dice paradigm, where we add a random number to the sum.
# N = number of dice, S = number of sides, R = result
roll_dice(N, S, R) :-
N1 #> 0,
R = random_between(1, S, R1),
N1 #= N-1,
roll_dice(N1, S, R1).
throws an error but neglects the sum anyway. I would normally use += in other languages.
A few things not quite right there:
R = random_between(1, S, R1) stores that structure in R, it does not generate random numbers.
R1 is used for "the random number you get for rolling one die" and "the sum of all the random numbers from rolling all the remaining dice" and it is unlikely those will be the same value, and when they isn't the same, that will fail.
There is no code to do the summing. (The equivalent of the Factorial video using F #= N * F1)
No recursive base case (the first line of the factorial from the video is not shown in your question, it is n_factorial(0, 1).). When N dice remaining gets down to 0, there is nothing to handle that case.
Here is one implementation:
:- use_module(library(clpfd)).
roll_dice(0, _, 0).
roll_dice(NDice, Sides, Sum) :-
NDice #> 0,
random_between(1, Sides, Roll),
Sum #= Roll + RunningTotal,
NDiceLeft #= NDice - 1,
roll_dice(NDiceLeft, Sides, RunningTotal).
while trying to obey the recursive nature of Prolog.
I guess that's important to understand; this can be done with less bolierplate and fewer temporary variables to name, e.g.:
roll_dice(NDice, Sides, Sum) :-
length(Rolls, NDice),
maplist(random(1, Sides), Rolls),
sum_list(Rolls, Sum).
which makes a list Rolls the right size to hold all the rolls, fills them in using maplist to apply random on each of them, and sums that list for the answer.
I'd do something along the lines of:
roll(N,S,R) :- positive_int(N), positive_int(S), roller(N,S,0,R) .
positive_int(N) :- integer(N), N > 0 .
roller(0,_,R,R) .
roller(N,S,T,R) :-
T1 is 1+random(S),
N1 is N-1,
roller(N1,S,T1,R)
.
Suppose I have a list like [1,[2,1,[2],[3,1,1,[[3]],1,[1]],1],2,1,2,1,3] and I want to delete every second occurrence of '1' from it for a resultant list of [1,[2,[2],[3,1,[[3]],1,[]],1],2,2,1,3]. So far what I've come up with is this:
delete_second_occurrence([], [], _, _).
delete_second_occurrence([X|L], [X|R], X, N) :-
0 is mod(N, 2),
N1 is N + 1,
delete_second_occurrence(L, R, X, N1).
delete_second_occurrence([X|L], R, X, N) :-
1 is mod(N, 2),
N1 is N + 1,
delete_second_occurrence(L, R, X, N1).
delete_second_occurrence([E|L], [E|R], X, N) :-
is_list(E),
delete_second_occurrence(E, R, X, N),
delete_second_occurrence(L, R, X, N).
delete_second_occurrence([E|L], [E|R], X, N) :-
delete_second_occurrence(L, R, X, N).
To clarify,
R is the resultant list
L is the input list
X is the element I want to be removed
N is the number of times X has been encountered
It removes every second occurrence in the lowermost level but does nothing for the nested lists. How would I go about removing the duplicates in the nested lists as well?
The main problem is the fourth clause:
delete_second_occurrence([E|L], [E|R], X, N) :-
is_list(E),
delete_second_occurrence(E, R, X, N),
delete_second_occurrence(L, R, X, N).
The second condition is true if R is the result of deleting every second occurrence of X in E. The third condition is true if R is the result of deleting every second occurrence of X in L. Furthermore, N must have the same value after calling delete_second_occurrence on E and L. Not many lists have these properties. There are two problems to address:
Choose a different variable name in the first invocation of delete_second_occurrence and update the head of the clause appropriately.
Introduce another argument that represents the state of the accumulator after the recursive call.
Instead of counting the number of times that X has been encountered, you can use a Boolean variable. There is no need to perform modular arithmetic. After doing this, you will notice that your program generates one correct solution and several incorrect ones. For example, consider the fifth clause:
delete_second_occurrence([E|L], [E|R], X, N) :-
delete_second_occurrence(L, R, X, N).
This clause states that [E|R] is the result of deleting every second occurrence of X in [E|L] if R is the result of deleting every second occurrence of X in L. This is not always true. For example, if N is 1 and E unifies with X, you certainly don't want to include E in the output list. Similarly, if E is a list that contains X, you probably shouldn't generate solutions that simply prepend E to the result of the recursive call.
I m trying to check if, in a list of lists, all sublist is equal to the length of the list of lists.
For example, if I have [[1,2],[3,4]] is true, because I have 2 lists
of 2 elements.
Otherwise, if I have
[[1],[2,3]] is false because have 2 lists but not all list has 2
elements
[[1,2],[2,3],[3,4]] is false because I have 2 lists and all list have
2 elements instead of two
.
I did these two function:
count([],0).
count([_H|T],N):-count(T,N1),N is N1+1 .
ma([],0).
ma([H|T],N):- count(H,M1),ma(T,N1), M1 is N1.
I did "count" (and work) for count element in a list and return N the number of elements in a list.
The "ma" function doesn't work because "count" is executed until 0, and return 2, after executing ma but until 1 step, and after making directly the M1 is N1, and obviously return false.
I wish to make M1 is N1 at end of the program (like in another programming language, but I think is the then't correct form.
EDIT:
Daniel suggest to use :
ma([H], N) :- length(H, N).
ma([H|T], N) :- length(H, N), ma(T, N).
But a list with 3 sublists all with 2 elements gives result 2, instead the result will be false(error) because N number of the list must be equal to N number of elements in ALL Sublist.
I will do on my own, without build-in predicate of prolog.
Here a very basic solution without built in predicates:
count_elements([],N,N).
count_elements([_|T],N,N0):-
N1 is N+1,
count_elements(T,N1,N0).
count_length_sub([],_).
count_length_sub([H|T],N):-
count_elements(H,0,N),
count_length_sub(T,N).
solve(L):-
count_elements(L,0,NO),
count_length_sub(L,NO).
?- solve([[1,2],[3,4]]).
true.
?- solve([[1,2],[2,3],[3,4]]).
false.
Your count/2 is like the length/2 builtin, except that the built-in has more instantiation patterns (try length(X, Y) and see). Prefer length/2.
You're right that your ma/2 predicate is unhelpful because 0 is not a length of a sublist. Basically, you've chosen the wrong base case here; your base case should be a list with exactly one item in it:
ma_1([H], N) :- length(H, N).
ma_1([H|T], N) :- length(H, N), ma(T, N).
You will need to wrap this in something that ensures the length matches the length of the outer list:
ma(L, N) :- length(L, N), ma_1(L, N).
Note that there is no need to obtain separate variables and assert their equality (your dance with N and N1). Prolog will simply fail, which is what you want, if N does not have the right value. (Side note, do not use is for unification. The purpose of is is to reduce an arithmetic expression on the right side to a value and assign it to the variable on the left, e.g. X is 2 + 3*4.)
Another approach would be to write your actual request in a logical form and write that instead. A logical form of this request would be something like "ma(L, N) holds if N is the length of L and for all items X of L, they are lists of length N as well". This looks like so:
ma(L, N) :-
length(L, N),
forall(member(X, L),
length(X, N)).
This has an advantage in that no spare choice points are left around, although worrying about that is usually premature optimization.
Another approach would be to employ maplist/N, which has the advantage that it will give you back lists with variables. Unfortunately, length/2 has its parameters in the wrong order so you can't do the really cute thing and just write maplist(length(2), L). However, you can make a flip/3 predicate that flips around the arguments:
flip(P, Y, X) :- call(P, X, Y).
ma(L, N) :- length(L, N), maplist(flip(length, N), L).
Or, you can import library(yall) and use its lambda expressions:
ma(L, N) :- length(L, N), maplist({N}/[X]>>length(X, N), L).
Both of these approaches allow solutions like these:
?- ma(X, N).
X = [],
N = 0 ;
X = [[_1976]],
N = 1 ;
X = [[_1982, _1988], [_1994, _2000]],
N = 2 ;
X = [[_1988, _1994, _2000], [_2006, _2012, _2018], [_2024, _2030, _2036]],
N = 3
...
I have a simple function below which takes 2 lists ( with the same size) and a variable which stores some result.
My intention was to compare the first list's head with the second one and increase the result by one, and return it.
But instead I get true / false.
myfunction( [], [], 0).
myfunction([H1|T1], [H2|T2], N) :-
H1 > H2 -> myfunction(T1, T2, N1 + 1); myfunction(T1, T2, N1), N is N1 .
You're treating Prolog like an imperative/procedural language, but it doesn't work that way. You should read through some Prolog tutorials and/or books.
In Prolog, you define a predicate which defines a relation. When you define a predicate with variables, you are saying that, These variables are related in such and such a way if.... If Prolog succeeds in verifying the relation is true, the predicate response with "true" or "yes". Otherwise, it responds with "false" or "no".
Here's a rework of what you're trying to do:
my_predicate([], [], 0).
This relation is the "base case" and says that the count of cases where the corresponding values in the first list are greater than the second when the lists are empty is 0.
my_predicate([H1|T1], [H2|T2], N) :-
my_predicate(T1, T2, N1),
( H1 > H2
-> N is N1 + 1
; N = N1
).
This relation says that N is the count of cases where the corresponding values in the first list are greater than the second if N1 is the count of cases for the tails, and N is N1 + 1 if the current head is greater, otherwise N is N1.
If you want to make it tail recursive for efficiency, you can use an accumulator:
my_predicate(L1, L2, N) :-
my_predicate(L1, L2, 0, N).
my_predicate([], [], N, N).
my_predicate([H1|T1], [H2|T2], A, N) :-
( H1 > H2
-> A1 is A + 1
; A1 = A
),
my_predicate(T1, T2, A1, N).
Note that the above definition of my_predicate/3 assumes you want failure if the lists are different length. If you don't want failure in those cases, you would need to redefine the base case(s).
I'm new in SWI-Prolog and I want to check prime function in Prolog.
prime(N) :-
N > 1,
M is N - 1,
check(N, M).
check(_, 1).
check(N, M) :-
M > 1,
R is N - M * N / M,
R > 0,
P is M - 1,
check(N, P).
but when I ask 2 + 2 or another operator like (*)/2, (/)/2,... in Prolog it says: undefined procedure: (+)/2.
I think it is for see or tell. I reassign see(user) and tell(user) but this error occurs again.
why?
In SWI prolog 6.0.2 division as you used it returns floating point number. So prime(13) for example will fail, as remainder is 0. Integer division uses operator //. But check prolog SWI functions rem and mod.
Also you would like to have a cut after first definition of check, otherwise prolog will explore the second definition, which will return false. Cut ensures that after it checked all natural numbers smaller than N, it stops with success.
Here is the corrected code which behaves as desired in SWI Prolog 6.0.2.
prime(N) :-
N > 1,
M is N - 1,
check(N, M).
check(_, 1) :- !.
check(N, M) :-
M > 1,
R is N mod M,
R > 0,
P is M - 1,
check(N, P).
About your error, check this out:
?- 2+2.
ERROR: Undefined procedure: (+)/2
?- X is 2+2.
X = 4
You're supposed to use is in Prolog to force the evaluation of arithmetic expressions. Try typing "help(is)." at SWI-Prolog's prompt.
But your algorithm is massively inefficient, on two accounts. First, you check the candidate number for divisibility by all its preceding numbers, while only those not greater than its square root are enough (if a*b=n and a >= sqrt(n) then b =< sqrt(n)).
Then, you test in reversed order. Multiples of smaller factors are much more frequent than of larger ones, so the testing will get cut off much much earlier when done in ascending order, making the overall program run much much faster. Lastly, no need to test by any even number except 2:
prime(2).
prime(N) :- N > 1,
N mod 2 > 0, % is odd
M is floor(sqrt(N+1)), % round-off paranoia
check(N, M, 3).
check(N, M, F) :- F>M.
check(N, M, F) :- F=<M,
N mod F > 0,
F1 is F + 2, % test by odds only
check(N, M, F1).
primesFromTo(F,T,X):-
between(F,T,X), prime(X).
You are mentioning see and tell: These are very old-fashioned built-in predicates. Better avoid them. Use [file] to load a file, and make to reload it.
For a better implementation of testing primes, see this answer.