Related
I am programming in Prolog looking from any given number (F), to multiply the even elements of a list; keeping those values that are not, developed the following and in fact the program "compiles" without any error but when entering values it only returns "false", where could I be wrong ?:
% base case
evenproduct(_,[],[]) :- !.
% recursive case
evenproduct(F,[X|Xs], [Y|Ys]) :-
Y is F*X,
X mod 2 =:= 0,
evenproduct(F, Xs, Ys), !.
Thanks!!
You shouldn't use cuts (the ! goal). Cuts are an advanced Prolog concept that are only useful once you are a much more advanced Prolog programmer. Before that, cuts will only confuse you. Also, cuts will usually not make your program succeed more often, but they will make it fail more often. Your problem is that your program fails too often! Cuts might be part of your problem.
Also, it's not quite correct that your program always returns false. Look, it does work for some inputs:
?- evenproduct(3, [2, 4, 6], Ys).
Ys = [6, 12, 18].
Namely, if the given list only contains even numbers, your program works exactly as intended. Good job so far!
What you now need to do is to also make this succeed for the case where one of the numbers in the list is odd. There is one main way of making a Prolog program succeed more often: Adding more clauses to some predicate.
Your definition of evenproduct/3 has two clauses so far. Maybe all the list processing predicates you've seen so far have always had exactly two clauses, one for "the base case" and one for "the recursive case". But it's perfectly fine, and often very necessary, to have several non-recursive or several recursive clauses. In your case, you can add the following clause to your program to make it work:
evenproduct(F,[X|Xs], [Y|Ys]) :-
Y = X,
X mod 2 =:= 1,
evenproduct(F, Xs, Ys).
So now you will have three clauses in total, one non-recursive and two recursive ones.
And now odd numbers are accepted as well:
?- evenproduct(3, [1, 2, 3, 7, 11, 22], Ys).
Ys = [1, 6, 3, 7, 11, 66] ;
false.
I am making a program that solves a puzzle. but I need to make a predicate that returns the transpose given a matrix(list of lists) and I can't use the predefined one. but whatever I do I can't get the predicate to work backwards without getting a stack limit exceeded, ex: trans([[1,2],[3,4]],X). returns [[1,3],[2,4]] but trans(X,[[1,3],[2,4]]). exceeds the stack limit.
here is the trans predicate:
trans(M,M1):-
length(M,L),
trans1(0,L,M,R).
trans1(N,N,_,[]).
trans1(I,N,M,M1):-
I1 is I+1,
column(M,I1,C),
trans1(I1,N,M,M2).
and here is the column predicate that I used:
row([H|_],1,H):-!.
row([_|T],I,X) :-
I1 is I-1,
row(T,I1,X).
column([],_,[]).
column([H|T], I, [R|X]):-
row(H, I, R),
column(T,I,X).
any idea how I can use trans give the list if I give its transpose?
Many years ago, I wrote my own transpose/2, as a part of my IL project. Here it is:
% row/columns transposition
%
transpose_col_row([], []).
transpose_col_row([U], B) :- gen(U, B).
transpose_col_row([H|T], R) :- transpose_col_row(T, TC), splash(H, TC, R).
gen([H|T], [[H]|RT]) :- gen(T,RT).
gen([], []).
splash([], [], []).
splash([H|T], [R|K], [[H|R]|U]) :-
splash(T,K,U).
Despite the code doesn't use anything complicated, it's not too easy to understand what it does, and, like your own, or SWI-Prolog library(clpfd) implementation, it is not 'reversible'.
Your code has many problems you need to solve (note: singletons warnings are errors, really), but assuming you can nail them down, and get a working trans(M,T), you could use a simple 'hack', swapping arguments after checking instantiation:
trans_rev(M,T) :- var(M) -> trans(T,M) ; trans(M,T).
Let's try with my own implementation, that is
transpose_col_row_rev(M,T) :-
var(M) -> transpose_col_row(T,M) ; transpose_col_row(M,T).
?- transpose_col_row_rev([[1,2]],T).
T = [[1], [2]]
?- transpose_col_row_rev(M,$T).
M = [[1, 2]],
T = [[1], [2]]
You can re-assemble the predicate by looking at the publicly available, free (as in beer), open-source SWI-Prolog code. Why people don't do that more often is a mystery to me. It is very easy, but still more difficult than someone just dumping the working code on you I guess.
First, here is the (somewhat cryptic) implementation of transpose/2 in library(clpfd):
lists_transpose([], []).
lists_transpose([L|Ls], Ts) :-
maplist(same_length(L), Ls),
foldl(transpose_, L, Ts, [L|Ls], _).
transpose_(_, Fs, Lists0, Lists) :-
maplist(list_first_rest, Lists0, Fs, Lists).
list_first_rest([L|Ls], L, Ls).
This uses a predicate same_length/2. It is defined in library(lists) and looks like this:
same_length([], []).
same_length([_|T1], [_|T2]) :-
same_length(T1, T2).
Pretty straight-forward.
Then it uses maplist and foldl. Are there allowed or not? If not, you can rewrite maplist(same_length(L), Ls) as:
all_same_length([], L).
all_same_length([X|Xs], L) :-
same_length(X, L),
all_same_length(Xs, L).
Stupid code that shouldn't be written manually but well.
You can then replace maplist(same_length(L), Ls) with all_same_length(Ls, L).
This leaves you with the foldl(transpose_, L, Ts, [L|Ls], _). This is the "cryptic" bit; this qualification was maybe meant as a compliment to the person who wrote it.
Either way, a fold written like this that ignores the last argument (the result) can be re-written as a loop not too different from the maplist above. The transpose_/4 used in the fold has a maplist in its definition, but I showed already how to do that.
Since this looks like homework I will let you figure it out on your own.
Cheat code: if you look far enough into the history of the library (all on github!) you might get super lucky and find a pre-foldl implementation of the same transpose.
how can I put all the pairs in a one list?
I have -
pair([H|T], [H,E]) :- member(E, T).
pair([_|T], P) :- pair(T, P).
and I want the answer will be a list of pairs.
so I try -
listPairs([],[Res1]):-
Res1=[].
listPairs(L,[Res2]):-
L=[H|T],
append(pair([H|T],[Res2]),listPairs(T,[Res2])).
but I miss something of the lists..
because it is not compile.
I don't really see what you aim to do with append/2. You can definitely not put goals that should be called in the append/3 because in that case, they will be seen as functors.
You can however easily use the findall/3 predicate which is implemented in nearly all Prolog systems (well at least all I have seen that are actively used):
listPairs(L,Pairs) :-
findall(Pair,pair(L,Pair),Pairs).
findall/3 works as follows:
findall(Format,Goal,List).
Here you specify a Goal (here pair(L,Pair)) and Prolog will call the Goal. Each time the Goal succeed, Prolog will suspend the interpreter and add en element formatted as Format to the List. When the Goal fails, the list of all Formats is returned.
If I run the query, I get:
?- listPairs([1,a,2,'5'],Pairs).
Pairs = [[1, a], [1, 2], [1, '5'], [a, 2], [a, '5'], [2, '5']].
Note that L must be grounded (as list, meaning without uninstantiated tail, an uninstantiated element is fine), since otherwise the number of pair/2 elements that you will generate is infinite and thus you will run out of global stack (or memory in general).
I'm trying to write a rule in prolog that requires me to build a list recursively. I'm being able to build that list but the issue is that I dont know how to stop that process for building the list. So, I need to write a rule that would stop building that list further.
This is what my rule looks like:
%a few rules that are supplementing the rule popular:
member(H,[H|T]).
member(X,[H|T]) :- member(X,T).
notmember(H,A) :- member(H,A), !, fail.
notmember(H,A).
size([],0).
size([H|T],N) :- size(T,N1), N is N1+1.
listhasx(X,A) :- article(A,_,_,_,R), member(X,R).
notlisthasx(X,A) :- listhasx(X,A), !, fail.
notlisthasx(X,A).
makelist(A,L) :- ________________________________________________________.
makelist(A,L) :- listhasx(X,B), notmember(B,L), N2 is B, makelist(N2,L2), L=[A|L2].
popular(X,0).
popular(X,N) :- listhasx(X,A), makelist(A,L), size(L,N1), N-1<N1.
So, basically, I need to write a rule for popular, which I have written already. But, it uses the makelist rule which is partially incomplete. To be specific, the first part of makelist needs to be completed, which would imply when the list should be stopped from building.
I would be really thankful if someone could help me out on this..
The easiest way to build a list of X such that they satisfy a goal
G, is to use the findall predicate. Here is an example:
?- [user].
p(3).
p(1).
p(2).
^D
Yes
?- p(X).
X = 3 ;
X = 1
?- findall(X, p(X), L).
L = [3, 1, 2]
The predicate finall/3 is part of the ISO core standard. So should
be found in most Prolog systems. Related predicates are bagof/3 and
setof/3.
Also useful are predicates from a module aggregate found in
many Prolog systems, or solution counting and limiting predicates
also found in many Prolog systems.
Bye
I've been given the question:
Define a predicate ordered/1, which checks if a list of integers is correctly in ascending order. For example, the goal ordered([1,3,7,11]) should succeed, as should the goal ordered([1,3,3,7]), whereas the goal ordered([1,7,3,9]) should fail.
So far I have this:
ordered([]).
ordered([N, M|Ns]):-
append(M, Ns, Tail),
ordered(Tail),
N =< M.
But it fails on every list.
I have deduced that the reason it fails is because it reaches the end number in the list then tries to compare that number against an empty list. Obviously this fails because you can't compare an integer to an empty list. Even if you could and it, say, returned 0 for an empty list, it would still return false as the number would be greater than 0, not less than.
I can't find a solution... Any ideas? Thanks, Jon.
Edit
So, some slightly amended code:
ordered([]).
ordered([N]):-
N >= 0.
ordered([N, M|Ns]):-
append(M, Ns, Tail),
ordered(Tail),
N =< M.
This now works for ordered([1]), but bigger lists still don't run correctly.
Should I include something like ordered([N, M|Ns]) in the definition?
(assuming this is homework, I hesitate to give a complete solution).
Looking at your code, try to find out how it would unify ?- ordered([1]).
Run this query mentally (or using trace/0) and see what it does, step by step, and how it computes its result.
Also, please try to get "returns a value" out of your mind when thinking prolog. Prolog predicates don't return anything.
I think your solution is not also tail-recursion-friendly.
Think something like that would do:
ordered([]) :-!.
ordered([_]):-!.
ordered([A,B|T]) :-
A =< B,
!,
ordered([B|T]).
If you are using SICStus Prolog,
my previous answer will not work, as the
clpfd library in SICStus Prolog
does not offer the library predicate
chain/3 included with
SWI-Prolog's clpfd library.
:- use_module(library(clpfd)).
:- assert(clpfd:full_answer).
Don't panic! Simply implement predicate ordered/1 like this:
ordered([]).
ordered([X|Xs]) :-
ordered_prev(Xs,X).
ordered_prev([] ,_ ).
ordered_prev([X1|Xs],X0) :-
X0 #=< X1,
ordered_prev(Xs,X1).
Let's see it in action with SICStus Prolog 4.3.2.
Here's the most general query:
?- ordered(Xs).
Xs = []
; Xs = [_A]
; Xs = [_A,_B], _A#=<_B, _A in inf..sup, _B in inf..sup
; Xs = [_A,_B,_C], _A#=<_B, _B#=<_C, _A in inf..sup, _B in inf..sup, _C in inf..sup
... % an infinity of solutions follows: omitted for the sake of brevity.
And here are the queries the OP suggested:
?- ordered([1,3,7,11]).
yes % succeeds deterministically
?- ordered([1,3,3,7]).
yes % succeeds deterministically
?- ordered([1,7,3,9]).
no
Note that both succeeding queries in above example did not leave any useless choicepoints behind, thanks to first argument indexing.
If your Prolog system supports clpfd, check if it offers the library predicate clpfd:chain/2.
:- use_module(library(clpfd)).
If so, simply write:
?- chain([1,3,7,11],#<).
true.
?- chain([1,3,3,7],#=<).
true.
?- chain([1,3,3,7],#<).
false.
?- chain([1,7,3,9],#<).
false.
You're quite right: according to your code there are only two possible ways a list can be ordered:
It's empty
The first two items are in the correct order, and the rest of the list is ordered
Those are certainly both correct statements, but what about the list [3]? Isn't that ordered too? Obviously a list with only one element is ordered, yet you have no provision for expressing that: it fits neither your base case nor your recursive case.
The single-element list is another case hiding here that you haven't addressed yet. Since this is independent of the two rules you've already defined, you might want to consider a way to address this special case separately.
Well that, in the end, was rediculously easy to fix.
Here is the correct code.
ordered([]).
ordered([N, M|Ns]):-
append([M], Ns, Tail),
ordered(Tail),
N =< M.
ordered([M]).
ordered([M]). deals with the single-element list as described above.
The real root of my problem was not including [] around the M in the append function.
Whats the ettiquette regarding awarding the correct answer? You've both helped muchly.
Jon
Don't use append/3.
edit1 to satisfy #false. In order to make it tail recursive friendly it has to eliminate backtracking. This is tail-recursive and only slight variation on #Xonix:
ordered([X|[]]):-!.
ordered([X,Y|Ys]) :-
X =< Y,
!,
ordered([Y|Ys]).
edit2 Take it a step further to eliminate lists that have less than two elements
ordered([X,Y|[]]):- X =< Y,!.
ordered([X,Y|Ys]) :-
X =< Y,
!,
ordered([Y|Ys]).