prolog, checking if all members of a list are unique without built-in predicates - prolog

I want to write the rule unique(List) that checks if all elements in List are unique. I'm not allowed to use member, but I am allowed to use 'not'. Therefore I wrote the rule 'member' myself.
I wrote this:
member(Element, [Element|_]).
member(Element, [_|List]) :-
member(Element, List).
unique([H|T]) :-
not(in_list(H, T)),
unique(T).
The member-rule is working, it checks if Element is a member of List. But the unique- rule doesn't work. For the unique-rule is was expecting it would check if H was in T and then do the same for the Header of the Tail and so on. The 'not' makes from a false statement a True-output.
When I run this rule with query ?-unique([1,2,3,4,5]) it gives False. So what's my mistake?

I just discoverd the solutions a few moments later.
I added this above:
unique([]).
unique([_,[]]).

Related

Using OR operator with different / non existent facts in Prolog

I have a fact:
loves(romeo, juliet).
then i have an 'or' rule:
dances(juliet) :- loves(romeo, juliet).
dances(juliet) :- dancer(juliet).
As you can see dancer fact does not exist but this should be no problem and dances(juliet) should return me true. Instead it returns me true and then throws an exsitence exception about dancer fact. Is there a way to write rules for non existent facts or rules? Do I need to check if the fact exists?
To achieve "failure if not existant", you can declare your predicate dynamic using the directive dynamic/1.
For example:
:- dynamic dancer/1.
If you add this directive to your program, you get:
?- dances(X).
X = juliet .
and no errors.
As far as I know there is not a way to use a nonexistant predicate. You could either check if the rule exists using the methods described in this question or you could just have some sort of placeholder to make sure that it does exist. A rule doesn't seem very useful if it is always false, so just write a couple of the true cases before you use it.
dancer(someone). %% To make sure that fact exists
loves(romeo, juliet).
dances(juliet) :- loves(romeo, juliet).
dances(juliet) :- exists(dancer), dancer(juliet).
Technically, you could do something like this:
dances(juliet) :- catch(dancer(juliet),
error(existence_error(procedure, dancer/1), _),
false
).
Which will run dancer(juliet) if the predicate exists, fail if it doesn't, and error otherwise.
I wouldn't say this is a very advisable thing to do though.

Prolog: Replace fact using fact

I am trying to implement a predicate replace(+OldFact,+NewFact)
which succeed only if the OldFact existed. If this succeeds then the
NewFact must be added to the set of clauses and the OldFact must be
deleted.
How do I do this?
I am not able to figure out clearly that how to achieve this
replacement using facts as well as how to use those assert and retract
database manipulation commands.
Thanks.
If I take the request at face value, you only need to use the predicates I mentioned in my comment. Your predicate would look something like this:
replace_existing_fact(OldFact, NewFact) :-
( call(OldFact)
-> retract(OldFact),
assertz(NewFact)
; true
).
I'm assuming that if the OldFact is not found, then you want the predicate simply to succeed. If failure of the predicate is acceptable if the old fact doesn't exist, this would be written simply:
replace_existing_fact(OldFact, NewFact) :-
call(OldFact),
retract(OldFact),
assertz(NewFact).
Note that if you have more than one same OldFact in the database, this predicate will backtrack for each one, replacing one occurrence on each backtrack. If you only want to replace one of them, you could use a cut:
replace_existing_fact(OldFact, NewFact) :-
call(OldFact), !, % Don't backtrack to find multiple instances of old fact
retract(OldFact),
assertz(NewFact).
Alternatively, if you want to replace each one without being prompted for backtracking:
replace_each_existing_fact(OldFact, NewFact) :-
forall(replace_existing_fact(OldFact, NewFact), true).

List check that elements are different

I would like to write a predicate different_from(Xs,X) which is a check that succeeds if and only if X is different from all the elements of the list Xs.
So the query
different_from([3,2,5],4)
should succeed but this following query should fail:
different_from([3,2,5],2)
Since the predicate is a check it should not instantiate either of its arguments.
thank you in advance for any help you can provide.
This is a very simple rule consisting of two clauses:
The first clause says that different_from is successful when the list is empty,
The second clause says that different_from is successful when the first element of the list does not match the element being searched, and also when different_from for the tail is successful as well.
Here is the same thing written in Prolog syntax:
different_from([], _).
different_from([H|T], E) :- E \= H, different_from(T, E).

Prolog program with lists and sublists

Hi I have to solve a problem in Prolog, that sounds like this: deletes all the sublists of a list that are increasing. For example the list [1,[2],[3,4],6] becomes [1,6].
So far I have tried this but it's not working. Any help please ?
domains
el=integer
list=el*
element=integer;list
lista=element*
goal
elim([1,[2],[3],4)],L),
write(L).
predicates
elim(lista,lista)
is_increasing(lista)
is_list(lista)
clauses
is_increasing([A,B|T]) :-
B>A,
is_increasing([B|T]).
is_list([_|_]).
is_list([]).
elim([],[]).
elim([E|Es],[E|Ts]) :-
is_list(E),
is_increasing(E),
elim(Es, Ts).
attempt to modularize your code: first write an is_increasing/1. Since it appears that a list of 1 element is increasing, you can do as simply as
is_increasing([A,B|T]) :- B > A, is_increasing([B|T]).
is_increasing([_]).
then you can use it to discard elements while copying. Beware to check that an element is a list before calling. Here is a possible definition
is_list([_|_]).
is_list([]).
edit
there is a bad declaration, as advised by mbratch
element=i(integer);l(list)
should be
element=integer;list
Also, you forgot is_increasing([_])., and anyway you're not using at all is_list or is_increasing.
The rule eliminating sublists of course should read
elim([E|Es], Ts) :- is_list(E), is_increasing(E), elim(Es, Ts).
just add the base case and a copy. i.e. elim is a 3 clauses predicate...
edit apart the rule above, you need only a base case
elim([],[]).
and a copy
elim([E|Es],[E|Ts]) :- elim(Es, Ts).
just try to understand why the order of rules is also important in Prolog...

Convert list into functor parameter

I got stuck to implement a logic. At some instance in my program I have a list say named as List.
The length of this List is variable and I don't know in advance. Now I have to pass this list in a functor to create a fact and I am unable to implement it. For eg:
if List is [first] then it should add the fact functor(first).
if List is [first,second] then it should add the fact functor(first,second).
if List is [first,second,third] then it should add the fact functor(first,second,third).
and so on...
I was trying by =.. but here I am unable to map that variable length constraint. For fixed length I am able to perform but I don't know in advance that how many elements will be there in list.
Any suggestions to implement this logic. Thanks.
I don't quite understand your problem with =.. but this worked for me:
assert_list(List) :-
Term =.. [my_functor|List],
assert(Term).
Note that I use my_functor instead of simply functor because functor/3 is a built-in predicate so you cannot assert ternary functor facts (functor(first, second, third)).
Calling it:
?- assert_list([first,second,third]).
true.
Checking that it works:
?- listing(my_functor).
:- dynamic user:my_functor/3.
user:my_functor(first, second, third).
true.
Note that technically, the different n-ary my_functor/n predicates are not the same predicates. You must use different queries in your program for each n. To circumvent this, you could simply assert the list as one and only argument of my_functor:
?- List = [first, second, third],
assert(my_functor(List)).
true.
?- listing(my_functor).
:- dynamic user:my_functor/3.
user:my_functor([first, second, third]).
true.
My SWI-Prolog version is 5.7.5.

Resources