Determine if list is valid or not prolog - prolog

I am writing a program that checks if a list is valid or not valid. Here is what I have so far and I know it should be short I just cannot grasp my mind around prolog
These are my facts
pkg(pkg_name)
pkg(p1)
pkg(p2)
dpnd(p2,p1)
My rule is going to be true_list()
this function will run as follows, if i select true_list([p1,p2]) then it should return true, if i do true_list([p1,p3,p2]) it should return false since p3 is not part of it. I have been looking at this for a while and feel like it should be so simple. I have tried this method
true_list(p1,p2):-package(package_name).
any assistance would be appreciated.

The best solution for this is to have a simple recursive predicate check every single element for existence.
for ?- true_list([p1,p2]).
pkg(pkg_name).
pkg(p1).
pkg(p2).
dpnd(p2,p1).
%your input is a list of elements [Element1, Element2, Element3...ElementN]
true_list([]).
true_list([H|T]) :-
(pkg(H) ->
(true_list(T)) ;
(fail)
).
This code checks every element in your list to see if it exists as a fact pkg and fails if it finds an element that is NOT a pkg. It also succeeds with an empty list.

Related

Prolog list length comparison return true/false

I am trying to write a function longer(S1,S2) which should be true if S1 is longer than S2, otherwise false. What I have so far is the following:
longer(A,nil).
longer(nil,B) :- false.
longer([A,AS],[B,BS]) :- longer(AS,BS).
But for some reason I cannot seem to get it to parse correctly when I provide for instance the input: longer([1,2],[1]).
But when I run the above through swi-prolog it return false.
Another example is running the: longer([1],nil) which also return false, even though it should be true by matching with list(cons(A,As)) where As = nil, finally matching the end clause.
What am I missing? Can someone point me in the right direction here, as I cannot see how this is not evaluating to true.
Edit: it should be noted that I am still fairly new to prolog at this point.
Update I have had some misunderstanding in relation to what is common prolog semantic. Including trying to force the program to yield a false value (probably being steered by my understanding of non-declarative language semantics). I have updated my answer with the inputs from #tiffi.
That is a solution that is pretty close to the thinking behind what you have come up with:
longer([_|_],[]).
longer([_|As], [_|Bs]):- longer(As,Bs).
Your idea with regard to the first clause (before your edit) could be expressed like this:
longer(A,[]):- is_list(A). %is_list/1 is inbuilt
However, that doesn't give you the right result, since the empty list is also a list. Thus you need to make sure that the first argument is a non-empty list.

Graph implementation (does graph include all vertices?)

Trying to implement following predicate, which takes on input
list of lists - one list = one tested graph T (as edges)
graph G itself (as edges)
and tests whether T includes all of the vertices of G. If it does(true) should return it. Basically it's list filtering.
What I have so far is:
covb([],G).
covb([H|R],G) :-
isItCov(G,H), covb(R,G).
isItCov([],H).
isItCov([V-W|R],H) :-
vertex(V,H),
vertex(W,H),
isItCov(R,H).
vertex(V,[V-_|G]).
vertex(V,[_-V|G]).
vertex(V,[_|G]):- vertex(V,G).
For covb([[a-c,c-b,c-d]],[a-b,a-c,a-d,c-d,b-c]) works fine(true). For covb([[a-c]],[a-b,a-c,a-d,c-d,b-c]) works fine too (false). I got an issue while I call it with multiple lists like covb([[a-c,c-b,c-d],[a-c]],[a-b,a-c,a-d,c-d,b-c]). which should work only for the first one.
I actually got two questions -
Why does it work for one list only?
I want to return items of lists of lists which passed the condition and returned true (that's the filtering part). How should I do that?
First of all, your program has a number of singleton variable warnings. Do not ignore singleton variable warnings. They can hide real bugs. Also, since more experienced Prolog users here know that programs with singleton variable warnings are not even worth running, they will (a) just see the warnings and decide that they are no longer interested in trying to help you, or (b) fix the warnings on their side, but then by definition they will be working on a program that is no longer the program you posted!
Now for your questions.
Why does it work for one list only?
It's really not clear what you are asking here, or just above with "covb([[a-c,c-b,c-d],[a-c]],[a-b,a-c,a-d,c-d,b-c]). which should work only for the first one."
This query does fail:
?- covb([[a-c,c-b,c-d],[a-c]],[a-b,a-c,a-d,c-d,b-c]).
false.
This comes down to testing each of the two lists:
?- isItCov([a-b,a-c,a-d,c-d,b-c], [a-c,c-b,c-d]).
true .
?- isItCov([a-b,a-c,a-d,c-d,b-c], [a-c]).
false.
The first list does cover the graph, while the second doesn't. Overall, your definition of covb/2 is written to succeed if all lists cover the graph. This is not the case, so your covb/2 query fails.
Was this what you wanted to know?
I want to return items of lists of lists which passed the condition and returned true (that's the filtering part). How should I do that?
You could see if your Prolog's documentation has something for the word "filter". On SWI-Prolog you can do this:
?- apropos(filter).
true.
This will point you to the include/3 predicate, which seems to do what you want:
?- include(isItCov([a-b,a-c,a-d,c-d,b-c]), [[a-c,c-b,c-d],[a-c]], Covers).
Covers = [[a-c, c-b, c-d]].
If you want to write a filter predicate for your concrete application, it might look something like this:
graph_covers(_Graph, [], []).
graph_covers(Graph, [Nodes|NodesRest], Covers) :-
( isItCov(Graph, Nodes)
-> Covers = [Nodes|CoversRest]
; Covers = CoversRest ),
graph_covers(Graph, NodesRest, CoversRest).
This is similar to your predicate, it just adds an extra argument to collect those node lists for which isItCov/2 succeeded. If it did not succeed, it continues with a list not containing that current node list.
?- graph_covers([a-b,a-c,a-d,c-d,b-c], [[a-c,c-b,c-d],[a-c]], Covers).
Covers = [[a-c, c-b, c-d]] ;
false.

base case to returning false on a condition prolog

I am working on a basic project in Prolog. I want to write a function that returns a number based on the input list. I also want to make sure that when the input list is empty, the result is false.
The function should be like this
parseList(List, N) where N is a number. I would like to know a way that returns False when we try
parseList([], N).
where N is any number.
I tried doing this for the base case
parseList([], False).
However,this does not seem to work.
Could anyone please help me with this? Thank You!
As Lurker said in his comment, in this instance, leaving out the empty list condition and handling the list of one element will cause the empty list to fail. However, in the more general case, if you want to declare a rule that fails, simply include false, because that can never be true, or fail which does the same. For example:
parseList([],_) :- false.
or (now deprecated)
parseList([],_) :- fail.
(where _ is used to denote an unimportant variable, otherwise a singleton-variable-warning will be triggered).

Prolog - getting a maximum value of set from a list of facts (using fail predicate)

Basically I have a list of facts like this:
set(x,2).
set(x,7).
set(x,10).
set(x,4).
I need to find the maximum element of this set.
Input: maximum(x, MaxElement)
Output: MaxElement = 10.
Now the idea itself isn't complicated and I saw many examples online myself. The problem is that I need to use the fail predicate.
Here was my idea (which doesn't work):
maximum(Set, Element1):-
set(Set,Element1),
set(Set,Element2),
Element2 > Element1,
fail.
maximum(Set, Element) :- set(Set, Element).
The idea here was that the first rule looks for every element which has a bigger element in the set. If there is a bigger element we fail and stop.
Then ideally for the biggest one (10), we would not fail and move on to the next rule which just sees that it is in the set and returns true.
But like this it still goes to the second rule with every number. Also using cut doesn't seem to work.
Any ideas guys?
You could simply use forall/2 predicate to examine every element like:
maximum(Set, Element1):-
set(Set,Element1),
forall(set(Set,Y),(Y>Element1->fail;true)).
Now querying:
?- maximum(x,X).
X = 10 ;
false.

Prolog beginner. How to take list as parameter and pass it on

I am a total beginner at Prolog. I am struggling with creating a rule, which takes a list as parameter and passes the list onto another rule. Here is my code:
combine([], '').
combine([L|List], Total) :-
combine(List, CombinedRest),
atom_concat(L, CombinedRest, Total).
findHeadline([W|Words], Combined) :-
combine(Words, Combined).
findHeadline2([Words], Combined) :-
combine(Words, Combined).
findHeadline works as expected, but findHeadline2 does not. Here is the output:
1 ?- findHeadline([billig, enkeltmand], Combination).
Combination = enkeltmand.
2 ?- findHeadline2([billig, enkeltmand], Combination).
false.
The output I was expecting from findHeadline was:
Combination = billigenkeltmand.
How can it be that this does not work?
I tried to utilize trace in SWI-prolog, but it gave me no clue whatsoever, as the findHeadline rule just exits immediately and does not call the combine rule at all.
It is not very clear what it is exactly that you are after. If you just want to concatenate a list of atoms to get one atom, use atomic_list_concat/2 available in SWI-Prolog:
?- atomic_list_concat([foo, bar, baz], C).
C = foobarbaz.
At the moment, your findHeadline2/2 reads:
"Take a list containing exactly one element, and combine/2 that element."
This is not what you are after, I have the feeling.
Your findHeadline/2, on the other hand, says:
"Take a list of at least one element, and combine/2 all elements except the first".
This is important: never ever ignore compilation warnings. You get code that does something, but you can be almost certain that it does not do what you want it to do, which is bad, or that if someone else reads your code, they will be confused, which is also bad.

Resources