The predicate if_/3 seems to be fairly popular among the few main contributors in the Prolog part of Stack Overflow.
This predicate is implemented as such, courtesy of #false:
if_(If_1, Then_0, Else_0) :-
call(If_1, T),
( T == true -> call(Then_0)
; T == false -> call(Else_0)
; nonvar(T) -> throw(error(type_error(boolean,T),_))
; /* var(T) */ throw(error(instantiation_error,_))
).
However, I have been unable to find a clear, simple, and concise explanation of what this predicate does, and what use it has compared to e.g. the classical if-then-else construct of Prolog if -> then ; else.
Most links I have found directly use this predicate and provide little explanation as to why it gets used, that a non-expert in Prolog could understand easily.
In old-fashioned Prolog code, the following pattern arises rather frequently:
predicate([], ...).
predicate([L|Ls], ...) :-
condition(L),
then(Ls, ...).
predicate([L|Ls], ...) :-
\+ condition(L),
else(Ls, ...).
I am using lists here as an example where this occurs (see for example include/3, exclude/3 etc.), although the pattern of course also occurs elsewhere.
The tragic is the following:
For an instantiated list, pattern matching can distinguish the first clause from the remaining two, but it cannot distinguish the second one from the last one because they both have '.'(_, _) as the primary functor and arity of their first argument.
The conditions in which the last two clauses apply are obviously mutually exclusive.
Thus, when everything is known, we want to obtain an efficient, deterministic predicate that does not leave choice points, and ideally does not even create choice points.
However, as long as not everything can be safely determined, we want to benefit from backtracking to see all solutions, so we cannot afford to commit to either of the clauses.
In summary, the existing constructs and language features all fall short in some way to express a pattern that often occurs in practice. Therefore, for decades, it seemed necessary to compromise. And you can make a pretty good guess in which direction the "compromises" usually go in the Prolog community: Almost invariably, correctness is sacrificed for efficiency in case of doubt. After all, who cares about correct results as long as your programs are fast, right? Therefore, until the invention of if_/3, this was frequently wrongly written as:
predicate([], ...).
predicate([L|Ls], ...) :-
( condition(L) ->
then(Ls, ...).
; else(Ls, ...).
)
The mistake in this is of course that when the elements are not sufficiently instantiated, then this may incorrectly commit to one branch even though both alternatives are logically possible. For this reason, using if-then-else is almost always declaratively wrong, and stands massively in the way of declarative debugging approaches due to its violation of the most elementary properties we expect from pure Prolog programs.
Using if_/3, you can write this as:
predicate([], ...).
predicate([L|Ls], ...) :-
if_(condition(L),
then(Ls, ...),
else(Ls, ...)).
and retain all desirable aspects. This is:
deterministic if everything can be safely decided
efficient in that it does not even create choice points
complete in that you never incorrectly commit to one particular branch.
The price of this is rather affordable: As Boris mentioned in the comments, you need to implement a reification. I have now some experience with this and found it rather easy with some practice.
Good news everyone: In many cases, condition is of the form (=)/2, or (#=)/2, and the first even ships with library(reif) for free.
For more information, see Indexing dif/2 by Ulrich Neumerkel and Stefan Kral!
Let's try to solve a simple problem using if_/3; for example, I will try to partition a list (sorted on a predicate p/2) in two lists: a prefix in which, for every element X, we have p(X, true), and a rest (in which, if the list was sorted on p/2, we would have p(X, false).
I will use the library reif as here. So, here is the complete code of my program:
:- use_module(reif).
pred_prefix(Pred_1, List, L_true, L_false) :-
pred_prefix_aux(List, Pred_1, L_true, L_false).
pred_prefix_aux([], _, [], []).
pred_prefix_aux([X|Xs], Pred_1, True, False) :-
if_( call(Pred_1, X),
( True = [X|True0],
pred_prefix_aux(Xs, Pred_1, True0, False)
),
( True = [],
False = [X|Xs]
)
).
The predicate passed to this meta-predicate will take two arguments: the first is the current list element, and the second will be either true or false. Ideally, this predicate will always succeed and not leave behind choice points.
In the first argument of if_/2, the predicate is evaluated with the current list element; the second argument is what happens when true; the third argument is what happens when false.
With this, I can split a list in leading as and a rest:
?- pred_prefix([X, B]>>(=(a, X, B)), [a,a,b], T, F).
T = [a, a],
F = [b].
?- pred_prefix([X, B]>>(=(a, X, B)), [b,c,d], T, F).
T = [],
F = [b, c, d].
?- pred_prefix([X, B]>>(=(a, X, B)), [b,a], T, F).
T = [],
F = [b, a].
?- pred_prefix([X, B]>>(=(a, X, B)), List, T, F).
List = T, T = F, F = [] ;
List = T, T = [a],
F = [] ;
List = T, T = [a, a],
F = [] ;
List = T, T = [a, a, a],
F = [] .
How can you get rid of leading 0's for example:
?- pred_prefix([X, B]>>(=(0, X, B)), [0,0,1,2,0,3], _, F).
F = [1, 2, 0, 3].
Of course, this could have been written much simpler:
drop_leading_zeros([], []).
drop_leading_zeros([X|Xs], Rest) :-
if_(=(0, X), drop_leading_zeros(Xs, Rest), [X|Xs] = Rest).
Here I have just removed all unnecessary arguments.
If you would have to do this without if_/3, you would have had to write:
drop_leading_zeros_a([], []).
drop_leading_zeros_a([X|Xs], Rest) :-
=(0, X, T),
( T == true -> drop_leading_zeros_a(Xs, Rest)
; T == false -> [X|Xs] = Rest
).
Here, we assume that =/3 will indeed always succeed without choice points and the T will always be either true or false.
And, if we didn't have =/3 either, you'd write:
drop_leading_zeros_full([], []).
drop_leading_zeros_full([X|Xs], Rest) :-
( X == 0 -> T = true
; X \= 0 -> T = false
; T = true, X = 0
; T = false, dif(0, X)
),
( T == true -> drop_leading_zeros_full(Xs, Rest)
; T == false -> [X|Xs] = Rest
).
which is not ideal. But now at least you can see for yourself, in one single place, what is actually going on.
PS: Please read the code and the top level interaction carefully.
Related
course(cmput325).
course(cmput175).
course(cmput201).
course(cmput204).
prerequisite(cmput204, cmput325).
prerequisite(cmput175, cmput201).
prerequisite(cmput175, cmput204).
I need to write a new predicate, which is
can_take(+L,?C).
Definition:
L is a given list of courses that a student has already taken. If C is also given,then the predicate should check whether the student has all the required courses for C. If C is a variable, then with backtracking, the predicate should produce one course at a time that the student can take now. Courses can be in any order, but each course should be generated only once, and you should not return any courses that the student has already taken.
Example:
?- findall(C, can_take([cmput175], C), L).
should return
L = [cmput201, cmput204].
Here is my predicate:
can_take(L,C) :- prerequisite(L,C).
can_take([L|List],C) :- prerequisite(L,C),can_take(List,C).
This predicate didn't return the correct result, and it just returned false. I think it is because I didn't determine the condition when L is empty, however, if I tried to add L \== [] in either of them. It still gave me error...what should I do so that this predicate will stop and give me result?
-------update-------
pre(X,C) :- prerequisite(X,C).
pre(X,C) :- prerequisite(X,Y), pre(Y,C).
pre2(C,L) :- findall(L1,pre(L1,C),L).
required(C,L) :- pre2(C,L1),sort(L1,L).
can_take([],_).
can_take(L,C) :- required(C,L).
can_take([L|List],C) :- prerequisite(L,C),can_take(List,C).
Here is my code test:
?- required(cmput325,L).
L = [cmput175, cmput204].
?- required(cmput204,L).
L = [cmput175].
?- can_take([cmput175],X).
X = cmput201 ;
X = cmput204 ;
?- findall(C, can_take([cmput175], C), L).
L = [cmput201, cmput204].
?- can_take([cmput204],cmput325).
false. (this one is OK)
?- can_take([cmput175,cmput204],cmput325).
true ;
false. (this one is OK)
?- can_take([cmput175],cmput204).
true ;
true ;
false.
the last one is not ok because I don't want it to return two true statements...so what I want is just let it stop when either second or last line returns true. For my assignment, I am not allowed to use cut operator !, is there any other way to do it?
(I will assume that you can take a course a second time, even if you have taken it already. That at least are the rules I know of.)
You can take a course, provided you have taken all required courses already.
There is no direct "all" in Prolog. But you can formulate this differently
You can take a course, provided there is no required course that you have not taken already.
can_take(Takens, Next) :-
course(Next),
iwhen( ground(Takens),
\+ ( prerequisite(Required, Next), \+ member(Required, Takens) ) ).
This uses iwhen/2 to guard against cases where Takens is not fully instantiated.
Note that there is a slight difference to your examples:
?- findall(C, can_take([cmput175], C), L).
L = [cmput175, cmput201, cmput204].
% ^^^^^^^^
Disclaimer
Your problem is inherently non-monotonic: By adding further facts for requirements you are reducing the number of possible courses you may take. As a beginner, rather stick to problems that are monotonic in nature. It is on this side where Prolog really excels.
duplicate([],[]).
duplicate([A|B],[A|B1]) :- not(member(A,B)), duplicate(B,B1).
duplicate([A|B],List) :- member(A,B), duplicate(B,List).
I wrote this predicate to remove duplicate from the list, but when I test it,
?- duplicate([a,b,c,a,d,c,b,a,e,f],N).
N = [d, c, b, a, e, f] ;
N = [d, c, b, a, e, f] ;
false.
Is there a way to just keep one result only, not two same results? (so it will only return one list).
Also, I am not allowed to use operators that modify the backtracking search, such as the cut operator !, the negation operators not, +, or the if-then-else operator with -> and ;
It would be grateful if someone could help me . :D
The actual reason for receiving more than one answer is the goal member(A,As). It produces multiple answers for duplicates in As.
?- member(a, [a,a]).
true
; true.
There are several ways out.
memberchk/2 or once/1
memberchk/2 is defined as
memberchk(X, Xs) :-
once(member(X, Xs)).
This removes alternate answers. But then, it may remove otherwise valid solutions too. Consider:
?- memberchk(X, [a,b]), b = X.
false.
?- b = X, memberchk(X, [a,b]), b = X.
b = X.
So memberchk/2 is sensitive to the precise instantiation, which makes it a very brittle, impure predicate.
But it has one good point: It sticks to just one answer for
?- memberchk(a, [a,a]).
true.
So what would be ideal is a definition that is both pure and sticking to the first element. Enter
memberd/2
memberd(X, [X|_Ys]).
memberd(X, [Y|Ys]) :-
dif(X, Y),
memberd(X, Ys).
In this definition, the recursive rule is only of relevance if the list element is different. Thus this rule will never apply to memberd(a, [a,a,a]).
Another problem in your definition is not(member(A,B)) which only behaves as intended, if A and B are sufficiently instantiated. Your definition fails for:
duplicate([a,X],[a,b]). although there is a solution: X = b.
Rather replace it by non_member/2.
Alternatively, in case you are interested in the most efficient solution, consider library(reif) available
for
SICStus and
SWI which leads to:
list_nub([], []).
list_nub([X|Xs], Ys0) :-
if_(memberd_t(X, Xs), Ys0 = Ys1, Ys0 = [X|Ys1]),
list_nub(Xs, Ys1).
Here's one way to remove all duplicates, not the most efficient but I think it's quite easy to understand the intention.
rm_duplicates(In, Out) :-
exclude(has_duplicate(In), In, Out).
has_duplicate(List, Case) :-
dif(I, J),
nth0(I, List, Case),
nth0(J, List, Case).
If you mean to make a list into a set:
list_to_set(List, Set).
It's documented: list_to_set/2
I'm trying to read through a list, check an element,if the element is in the KB,do something do it and add it to another list, if it's not in the KB then add it to another, third list.
I keep thinking in terms of procedural logic and can't really get my head around it. This is what I makes sense to me - but it doesn't work...
//KB
r([a|X],Y,[gone|X]).
r([c|X],Y,[gone|X]).
r([b|X],Y,[known|X]).
r([d|X],Y,[known2|X]).
simplify([X|List],[X|NW],Result) :-
r(List,Nw,NewList),
!,
simplify2(NewList,Nw,Result).
simplify2([W|Words],Nw,[W|NewWords]) :-
simplify2(Words,Nw,NewWords).
simplify2([],[],[]).
Query:
?- simplify([a,b,c,d,e,f],X,Y).
I want:
X = [e,f]
Y = [gone,known,gone,known2]
but the above gives X = [a|mem_address] and Y = [d,e].
Let's first fix the syntax:
Rest-of-line comments in Prolog start with % not //.
Remove the second argument from r/3; it has not purpose.
MW -> Mw in simplify/3.
Insert spaces in between arguments (not syntactically incorrect, but slightly challenging to read).
Now let's remove some redundancies:
In r/2 you do not really need the list tails.
Also, we do not need a list in order to state that some term is 'known' or 'gone'.
simplify/3 and simplify2/3 can be merged into the same predicate.
Now let's add some new stuff:
Declare r/2 as dynamic. This allows the KB to be altered using assert/1 and retract/1.
Use consistent naming for variables. E.g., H for list head, T for list tail, and L for (full) list.
We get the following:
:- dynamic(r/2).
r(a, gone).
r(c, gone).
r(b, known).
r(d, known2).
simplify([], [], []).
simplify([H|T1], L2, L3):-
( r(H, Status)
-> L2 = T2,
L3 = [Status|T3]
; L2 = [H|T2],
L3 = T3
),
simplify(T1, T2, T3).
With the desired behavior:
?- simplify([a,b,c,d,e,f],X,Y).
X = [e, f],
Y = [gone, known, gone, known2].
Notice how in the above I have performed the following steps:
I try to get syntactically valid Prolog.
Once the program has valid syntax, I try to simplify it while keeping the behavior stable/intact.
Only, when the code is both syntactically valid and simplified, I start altering it in order to achieve the intended behavior.
Edit: Thanks to false for pointing to non-steadfast behavior. The program was edited accordingly.
Well, first you need to collect the data from the KB (actually, the common term is Database) using setof. And then it's simple:
r([a|X],Y,[gone|X]).
r([c|X],Y,[gone|X]).
r([b|X],Y,[known|X]).
r([d|X],Y,[known2|X]).
kb(L) :- setof((A,B), r([A|_],_,[B|_]), L).
simplify([], [], []).
simplify([H|T], T1, [H2|T2]) :-
kb(L),
member((H,H2), L),
simplify(T, T1, T2).
simplify([H|T], [H|T1], T2) :-
simplify(T, T1, T2).
I'm learning swi Prolog and I wanted to create predicate that adds +2 for each element.
So I wrote something like this:
addUp([],_).
addUp([H|T],R):-addUp(T,R),is_list(R)->append([H+2],R,R);R=[H+2|[]].
addUp([1,2],X).
But it always returns false. Why?
First an advice: learn to use maplist/3: with that you will write
addUp(Xs, Ys) :- maplist(addUp2, Xs, Ys).
addUp2(X, Y) :- Y is X + 2.
or better, a more reusable snippet...
addUp(Xs, Ys) :- maplist(addUp(2), Xs, Ys).
addUp(N, X, Y) :- Y is X + N.
Anyway, arithmetic in Prolog must be evaluated 'explicitly', and your code must be simplified a lot to work
addUp([], []).
addUp([H|T], [H1|T1]) :- H1 is H+2, addUp(T, T1).
But it always returns false. Why?
Your definition does not always fail:
?- addUp([1],X).
X = [1+2].
So sometimes it succeeds. And it seems that this case is more or less what you wanted. Where else does it succeed? In other programming languages you would have to guess or, heaven forbid, read the program. In Prolog, there is no need for this. Simply find a good query. A good candidate is the most general query:
?- addUp(Xs,Ys).
Xs = [] ...
So your definition succeeds for Xs equal to [], and Ys equal to ... well, equal to anything. Therefore, this answer is too general.
Another goal catches my eye: is_list(R)->append([H+2],R,R). Let's imagine, when this will be true. For R = [] not, nor for R = [_]. In fact, there is no length, where this will be true.
Now, we can start fixing your program. See chac/CapelliC's suggestion.
I am working on a scenario in Prolog (eclipse) wherein I need a list structure to be reformatted.
I have a list of the form:
MyList = [a,b,c].
I was trying to see if I can flatten the list to a single element with all the commas replaced with the + operator.
So my result list would look like:
ResultList = [a+b+c]
which is a single element list. The length of the initial list is arbitrary.
I know prolog is not suited for such operations, but can this be done?
here it is, in standard Prolog. I think there should be no difference with Eclipse:
list_to_op([X,Y|T], [R]) :-
list_to_op(T, X+Y, R).
edit: bug noted by false
list_to_op([X], [X]).
list_to_op([X], R, R+X).
list_to_op([X|T], R, Q) :-
list_to_op(T, R+X, Q).
test:
?- list_to_op([a,b,c],X).
X = [a+b+c] .
The accumulator is required to give the appropriate associativity: the simpler and more intuitive definition
list_to_op1([X], X).
list_to_op1([X|R], X+T) :-
list_to_op1(R, T).
gives
?- list_to_op1([a,b,c],X).
X = a+ (b+c) .
If evaluation order is important, use list_to_op.
edit:
there is a bug: list_to_op([a,b],X) fails.
here the correction, as often happens, it's a simplification:
list_to_op([], R, R).
list_to_op([X|T], R, Q) :-
list_to_op(T, R+X, Q).
This may help
flatten_list(A,[B]) :- flatten_list_inner(A,B).
flatten_list_inner([A],A).
flatten_list_inner([H|T],H+Y) :- flatten_list_inner(T,Y).
The output is slightly different from what you wanted. It is currently [a + (b + c)]
How about this non-recursive version..
list_to_op(L, Res) :-
concat_atom(L, '+', Atom),
Res = [Atom].
?- list_to_op([a,b,c], X).
X = ['a+b+c'].
Edit: This works in Swi-prolog.. not sure about Eclipse.