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)
.
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 am beginner in Prolog programming. I wrote this program to sum the atomic of a deep list with accumulator.
deep_sum(Xs, N) :- deep_sum(Xs, 0, N).
deep_sum([], N, N).
deep_sum([X|Y], M, N) :- atomic(X), Q is M + X, deep_sum(Y, Q, N).
deep_sum([X|Y], M, N) :- M is P + Q, deep_sum(X, P, N), deep_sum(Y, Q, N).
Why do I get "ERROR: is/2: Arguments are not sufficiently instantiated"?
It works fine without accumulator:
deep_sum([], 0).
deep_sum([X|Y], S) :- atomic(X), !, deep_sum(Y, Q), S is Q + X.
deep_sum([X|Y], S) :- deep_sum(X, P), deep_sum(Y, Q), S is P + Q.
The problem is with your last clause:
deep_sum([X|Y], M, N) :- M is P+Q, deep_sum(X,P,N), deep_sum(Y,Q,N).
The direct issue of the error is that neither P nor Q have a value when M is P+Q is executed. Just moving it to the back won't solve it though, the clause has more issues.
Let's take a look at the recursive calls. deep_sum(X,P,N) in words means "N is the deep sum of the head (X), given accumulator P". There are two issues here: P does not have a value, and N is supposed to be the total sum of the entire list, not just the head.
The same issues are there in the second recursive call. The accumulator Q does not have a value yet, and again N is used as the result. So now N has 3 meanings: deep sum of the head, deep sum of the tail, and deep sum of the entire list! Obviously something is not right there.
Let's try to put in words how the recursive rule should behave. The result N should be equal to the sum of a) the current accumulator, b) the deep sum of the head and c) the deep sum of the tail. a and b can be easily combined: simply pass in the current accumulator as the accumulator for the recursive call: deep_sum(X, M, N1). Here I use another variable N1 to hold this result. Now we just have to sum this with the deep sum of the tail. Again, we can simply pass N1 as accumulator for the recursive call, and everything will be accumulated as expected.
Putting everything together, your recursive rule should look like this:
deep_sum([X|Y], M, N) :-
deep_sum(X, M, N1),
deep_sum(Y, N1, N).
For completeness, my deep_sum/3 implementation would look something like this:
deep_sum(X, M, N) :-
number(X),
N is M + X.
deep_sum([], N, N).
deep_sum([X|Y], M, N) :-
deep_sum(X, M, N1),
deep_sum(Y, N1, N).
The main differences are:
Only one recursive clause; the clause where you handle numbers doesn't need to be recursive.
number/1 instead ofatomic/1, so you don't attempt to add strings or so.
Rearranged the order of the clauses to not leave any useless choice point once the calculation is done.
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.