Using a functor - prolog

Following code accepts a index , a list and it deletes every nth occurance of that index in the list and returns a new list.
deleteNTerm(N,L1,L2) :- deleteNTerm(L1,N,L2,N).
deleteNTerm([],_,[],_).
deleteNTerm([_|Xs],N,Ys,1) :- deleteNTerm(Xs,N,Ys,N).
deleteNTerm([X|Xs],N,[X|Ys],K) :- K > 1, K1 is K - 1, deleteNTerm(Xs,N,Ys,K1).
So for the following query
?- deleteNTerm(2,[1,2,3,4,5,6,7],Result).
Result = [1,3,5,7].
However I want my code to accept a functor instead so i get
?-deleteNterm(2,f(1,2,3,4,5,6,7),Result).
Result f(1,3,5,7)
How to achieve this?.

You can break down a term into its functor and arguments using the (appropriately named) predicate functor. This being prolog, it is also used to build a term from those components. For example: functor(A,f,3) will yield A = f(_G2130, _G2131, _G2132).
Actually, what would be more helpful would be =..:
3 ?- f(1,3,5,7) =.. X.
X = [f, 1, 3, 5, 7].
4 ?- X =.. [f,1,3,5,7].
X = f(1, 3, 5, 7).

Related

Prolog check if list X has any duplicates

I have the function already but it is not working exactly as I want it to. The function I have is below..
isSet(List) :-
\+ (
select(Element, List, Tail),
select(Element, Tail, _)
).
When I do isSet([1,2,3]) it gives me true which is expected. When I do isSet([1,1,2]) it gives me false which is also what I expect and is correct. My question is how can I pass a list that is already made? For example If I do X = [1,2,3] and than pass it as a argument like isSet(X) it should give me true but instead it generates an error.
What can I do to fix this?
Edit:
?- [db].
true.
?- X = [1,2,3].
X = [1, 2, 3].
?- isSet(X).
false.
?- X = (1,2,3).
X = (1, 2, 3).
?- isSet(X).
false.
?- X = [1,1,2].
X = [1, 1, 2].
?- isSet(X).
false.
SWI-Prolog allows the form $Xs to access a variable from a previous query. E.g.:
?- Xs=[1,2,3].
Xs = [1, 2, 3].
?- isSet($Xs).
Xs = [1, 2, 3].
?- isSet([1|$Xs]).
false.
BTW, it's slightly more efficient to write your code like this (and I suggest using Rest rather than Tail: the latter is typically used in the form List=[Head|Tail]):
isSet(List) :-
\+ ( select(Element, List, Rest),
member(Element, Rest)
).
Also, you can't write a list like this: X = (1,2,3) ... that's actually something different:
?- write_canonical((1,2,3)), nl.
','(1,','(2,3))
true.
As there are discussions on how to best define the concept of "sets represented by lists", I humbly submit the following:
real_actual_set([]).
real_actual_set([X | Xs]) :-
nonmember_of(X, Xs),
real_actual_set(Xs).
nonmember_of(_X, []).
nonmember_of(X, [Y | Ys]) :-
dif(X, Y),
nonmember_of(X, Ys).
This is pure and works properly even in the presence of variables, including the most general query, and any lists containing variables that we would try to bind later:
?- real_actual_set([1, 2, 3]).
true .
?- real_actual_set([1, 1, 2]).
false.
?- real_actual_set([A, B, C]).
dif(A, C),
dif(A, B),
dif(B, C).
?- real_actual_set([A, A, B]).
false.
?- real_actual_set(Set).
Set = [] ;
Set = [_2222] ;
Set = [_2672, _2678],
dif(_2672, _2678) ;
Set = [_2970, _2976, _2982],
dif(_2970, _2982),
dif(_2970, _2976),
dif(_2976, _2982) ;
Set = [_3388, _3394, _3400, _3406],
dif(_3388, _3406),
dif(_3388, _3400),
dif(_3388, _3394),
dif(_3400, _3406),
dif(_3394, _3400),
dif(_3394, _3406) .
?- real_actual_set([A, B, C]), A = 1, B = 2, C = 3.
A = 1,
B = 2,
C = 3.
?- real_actual_set([A, B, C]), A = 1, B = 1, C = 3.
false.
This is quadratic, so it's "less performant" than other approaches. But as John Ousterhout is quoted, "The best performance improvement is the transition from the nonworking state to the working state."
The correct way to check if a list is a set in Prolog is to sort it, removing duplicates, and check if its length is still the same. This is correct for all kinds of reasons, from very pragmatic (easy to program) to purely theoretic (it is the only robust approach to checking if a singly linked list is a set).
"But this is not what I asked" sure it isn't.
is_set(List) :-
sort(List, Sorted),
length(List, N),
length(Sorted, N).
Don't throw Bloom filters and the like at me, at least not without proper justification.
To address the comments by #IsabelleNewbie, if you really want to use attributed variables to make sure that a list will forever remain a set under unification, you would do:
all_different([]).
all_different([H|T]) :-
maplist(dif(H), T),
all_different(T).
but this is a different thing altogether. You also shouldn't use it unless you want to take a list with variables and make sure no two elements in this list will ever unify. You get answers like this (in SWI-Prolog):
?- all_different(X).
X = [] ;
X = [_] ;
X = [_A, _B],
dif(_A, _B) ;
X = [_A, _B, _C],
dif(_A, _B),
dif(_A, _C),
dif(_B, _C) ;
X = [_A, _B, _C, _D],
dif(_A, _B),
dif(_A, _D),
dif(_A, _C),
dif(_B, _D),
dif(_B, _C),
dif(_C, _D) .
I suspect you can find this code in other places too.
For example If I do X = [1,2,3] and than pass it as a argument like isSet(X) it should give me true but instead it generates an error.
You should show us exactly what you tried!
This works:
?- Xs = [1, 2, 3], isSet(Xs).
Xs = [1, 2, 3].
Note that both parts (binding Xs and testing it) are in one query. Maybe you tried entering them separately:
?- Xs = [1, 2, 3].
Xs = [1, 2, 3].
?- isSet(Xs).
false.
This doesn't work because the value of Xs is not saved from one query to the next. This still isn't an error, though. However, it is not great behavior because failing for isSet(Xs) seems to imply that no sets exist at all.

How do I implement in Prolog the predicate list_for_set

How do I implement in Prolog the predicate list_for_set(Xs, Cs) where Cs is a list that contains the same elements as Xs, in the order of its first occurrence, but whose number of occurrences is only 1. For example, the query
? - list_for_set([1, a, 3.3, a, 1.4], Cs).
it happens only for Cs = [1, a, 3,4]. The consultation
? - list_for_set ([1, a, 3,3, a, 1,4], [a, 1,3,4])
must fail.
The Cs list of the previous statement will be called a set list, that is, a list with only one occurrence of each element.
Ok, there is some trickery involved.
foofilter([],_,_-T) :- T=[]. % close difflist
foofilter([L|Ls],Seen,H-T) :-
member(L,Seen),
!,
foofilter(Ls,Seen,H-T).
foofilter([L|Ls],Seen,H-T) :-
\+member(L,Seen),
!,
T=[L|NewT],
foofilter(Ls,[L|Seen],H-NewT).
:-begin_tests(filter).
data([1, a, 3, 3, a, 1, 4]).
test(one) :- data(L),
DiffList=[[]|T]-T, % Assume [] is never in L
foofilter(L,[],DiffList),
DiffList=[_|Result]-_,
format("~q ==> ~q\n",[L,Result]),
Result = [1,a,3,4].
:-end_tests(filter).
rt :- run_tests(filter).
Run tests:
?- rt.
% PL-Unit: filter [1,a,3,3,a,1,4] ==> [1,a,3,4]
. done
% test passed
true.
Someone will probably come up with a one-liner.

Get index of given element in list

I am trying to solve some basic puzzles to learn prolog. I am trying to get the index of a given element in a list with recursion. I got stuck trying to solve the problem and I am not sure why. When I execute this it only returns "false" instead of the index.
elem(_, [], 0).
elem(E, [E | T], RES) :-
elem(E, T, CUR_RES), RES is CUR_RES + 1.
An example query I use to check the code elem(2, [1, 2], X).
Your problem with
elem(2, [1, 2], X).
is that when it tries to unify with the base case
elem(_, [], 0).
it fails because the second parameter is not empty.
When it tries to unify with the recursive case
elem(E, [E | T], RES) :-
elem(E, T, CUR_RES),
RES is CUR_RES + 1.
E is 2, which requires the list to be [2|T] but since the list is [1,2] it also can not unify.
This is closer to what you want
elem(E,[E|_],0).
elem(E,[_|T],Res) :-
elem(E,T,Cur_rest),
Res is Cur_rest + 1.
Example runs:
?- elem(2, [1, 2], X).
X = 1 ;
false.
?- elem(1, [1, 2], X).
X = 0 ;
false.
?- elem(4, [1,2,3,4,5], X).
X = 3 ;
false.
You need to do the matching for the value you are seeking in the base case and not the recursive case. Once you do that the rest of changes follow as needed.

PROLOG defining 'delete' predicate

delete(X,[X|R],[_|R]).
delete(X,[F|R],[F|S]) :-
delete(X,R,S).
Above is my definition of delete predicate, for delete(X,L,R), intended to delete every occurrence of X in L with result R.
I had queried below, and get "G2397797". What does this string stand for?
?- delete(1,[1,2,3,4,5],X).
X = [_G2397797, 2, 3, 4, 5] .
If you simply correct your first clause and remove the unnecessary anonymous variable, you would get:
delete_each(X, [X|L], L).
delete_each(X, [Y|Ys], [Y|Zs]) :-
delete_each(X, Ys, Zs).
This will use unification, and delete each occurrence of X in the list upon backtracking:
?- delete_each(a, [a,b,a,c], R).
R = [b, a, c] ;
R = [a, b, c] ;
false.
Do you see how this is identical to select/3?
If you want to delete all occurrences of X in the list, you can see the answer by #coder.
In the answer you get X = [_G2397797, 2, 3, 4, 5] . , _G2397797 is not a string it is a variable that is not instantiated. This is due to the clause:
delete(X,[X|R],[_|R]).
which places in the output list an anonymous variable "_". You could write delete(X,[X|R],R).
But this has multiple problems. Firstly it only deletes the first occurrence of X not all because in the above clause when you find one you succeed. Also you haven't thought the case of empty list which is also the base case of the recursion. Finally in your second clause you haven't applied any rule that says F and X differ and this clause give wrong results when F equals to X.
So you could write:
delete(_,[],[]).
delete(X,[X|R],S):-delete(X,R,S).
delete(X,[F|R],[F|S]):-dif(X,F),delete(R,S).

Prolog does not end calculation?

This is rather a technical question I think, I am trying to write a program that will find me all sub-sets of size K of the integers 1,2,...,N.
In here I've asked about a sub-set function that I'm using. The fixed version is:
subs(0,[],X).
subs(N,[A|R1],[A|R2]):-
N>0,
N1 is N-1,
subs(N1,R1,R2).
subs(N,[A|R1],[B|R2]):-
N>0,
subs(N,[A|R1],R2).
Later I wrote two functions to help me find the last element in a set and the sub-set of all element except the last (because [A|Rest] means A is the first and Rest is from number 2 to last, but I'd like the opposite - having the last elements and all the elements from the first to the one before the last). The functions are:
lastOf(A,[A]).
lastOf(A,[B|R]):-
lastOf(A,R).
subLast([],[X]).
subLast([A|R1],[A|R2]):-
subLast(R1,R2).
Now I wrote a function that creates a list of the first N natural numbers:
setOf(0,[]).
setOf(N,Nums):-
lastOf(N,Nums),
N>0, N1 is N-1,
subLast(NeoNums,Nums),
setOf(N1, NeoNums).
To combine all the above I have:
choose(K,N,X):-
setOf(N,Y),
subs(K,X,Y).
Running it, for example on 2 and 4, I get:
?-choose(2,4,X).
X = [1, 2] ;
X = [1, 3] ;
X = [1, 4] ;
X = [2, 3] ;
X = [2, 4] ;
X = [3, 4] ;
abort
% Execution Aborted
14 ?- ERROR: Stream user_input:6:143 Syntax error: Unexpected end of clause
These are all the correct outputs, but the problem is that after every time I press enter for a (possible) next answer, I get the next one, apart from the last, in which I have to forcefully abort, as it seems like the programs gets stuck in an infinite loop of some sort.
Can anyone assist?
I'm using SWI-Prolog.
If you're using SWI-Prolog, you can also use clpfd! Here's a clpfd variant of choose/3:
:- use_module(library(clpfd)).
choose(K,N,Zs) :-
length(Zs,K),
Zs ins 1..N,
chain(Zs,#<),
labeling([],Zs).
That's it! And here's the query you gave in the question:
?- choose(2,4,Zs).
Zs = [1,2] ;
Zs = [1,3] ;
Zs = [1,4] ;
Zs = [2,3] ;
Zs = [2,4] ;
Zs = [3,4]. % the goal `choose(2,4,Zs)` terminates
The setOf is the problem here. More specifically - lastOf, which is generating an infinite number of possible lists ending with N. Anyway, setOf can be implemented much easier and in much more readable way (and which is terminating):
setOf(0, []).
setOf(N, [N|T]) :-
N > 0,
N1 is N-1,
setOf(N1, T).
This is if you don't care about the reverse order of the numbers. Otherwise by introducing a helper predicate:
setOf(N, X) :- range(1, N, X).
% range(LowerBound, UpperBound, ResultList)
range(L, L, [L]).
range(L, U, [L|T]) :-
L < U,
L1 is L + 1,
range(L1, U, T).

Resources