Prolog- Returning elements from facts - prolog

i encounter a problem with facts. Let's say i got 3 facts and check(X) question.
fact(a,b).
fact(b,c).
fact(a,d).
check(X):-
//some calculation with fact()
How to make above question to return list of elements for given X from all facts?
For instance: check(a) would give result b and d. So i can use this const later.
check(b) would return c. I would be grateful for help!

You need an extra argument for the list. So you cannot call it check/1 having a single argument, but — let's say — related_to/2.
related_to(X, Ys) :-
setof(Y, fact(X, Y), Ys).
Sample queries:
?- related_to(a, Xs).
Xs = [b, d].
?- related_to(b, Xs).
Xs = [c].
?- related_to(d, Xs).
false.
?- related_to(X, Xs).
X = a, Xs = [b,d]
; X = b, Xs = [c].
Note that the relation will fail for inexistent nodes like d above. On the other hand, you can even ask the most general goal getting all possible answers at once.
Also note that this relation is not monotone: If you add further facts, previously obtained results no longer hold. Like by adding fact(a,f) the goal related_to(a, [b,d]) no longer holds. Instead related_to(a,[b,d,f]) now holds.

Related

Prolog, understanding append/3

?- append([], [X1], [a,b]).
Why does this return no and not
X1 = a,b
Since
? - append([], [a,b], [a,b])
returns yes?
To understand a Prolog program you have two choices:
Think about the program as you do this in other programming languages by simulating the moves of the processor. This will lead to your mental exasperation very soon unless your name is Ryzen or in other words:
You are a processor
Let Prolog do the thinking and use Prolog to understand programs.
Whenever you see a failing goal, narrow down the reason why the goal fails by generalizing that goal (by replacing some term by a variable). You do not need to understand the precise definition at all. It suffices to try things out. In the case of your query
?- append([], [X1], [a,b]).
false.
We have three arguments. Maybe the first is the culprit? So I will replace it by a new variable:
?- append(Xs, [X1], [a,b]).
Xs = [a], X1 = b
; false.
Nailed it! Changing the first argument will lead to success. But what about the second argument?
?- append([], Ys, [a,b]).
Ys = [a, b].
Again, culprit, too. And now for the third:
?- append([], [X1], Zs).
Zs = [X1].
Verdict: All three kind-of guilty. That is, it suffices to blame one of them. Which one is up to you to choose.
Do this whenever you encounter a failing goal. It will help you gain the relational view that makes Prolog such a special language.
And if we are at it. It often helps to consider maximal failing generalizations. That is, generalizations that still fail but where each further step leads to success. In your example this is:
?- append([], [X1], [a,b]). % original query
false.
?- append([], [_], [_,_|_]). % maximal failing generalization
false.
From this you can already draw some conclusions:
The lists' elements are irrelevant.
Only the length of the three lists is of relevance
The third list needs to be two elements or longer.
See: append/3
append(?List1, ?List2, ?List1AndList2)
List1AndList2 is the concatenation of List1 and List2
So for
?- append([], [X1], [a,b]).
[] is the empty list and [X1] is a list with a variable X1
If you run the query like this
?- append([],[X1],A).
you get
A = [X1].
which means that A is the concatenation of [] and [X1].
In your query it is asking if the concatenation of [] and [X1] is [a,b] which is false, or no.
For your second query
? - append([], [a,b], [a,b])
it is asking if the concatenation of [] and [a,b] is [a,b] which is true, or yes.

Prolog: lexicographic comparison and split a list

Given atom x, I am trying to split a list into one with atoms smaller than x and one with atoms equal to or greater than x.
For example)
%% split(d,[a,b,c,d,e,f],AtomSmall, AtomBig) should give me
%% AtomSmall = [a,b,c], AtomBig = [d,e,f]
Below is what I've tried so far. I get the concept.However my code includes the atom that is equivalent to x in AtomSmall list, not AtomBig, although I check the case with before predicate.
For example)
%% split(d,[a,b,c,d,e,f],AtomSmall, AtomBig) gives me
%% AtomSmall = [a,b,c,d], AtomBig = [e,f]
before(X,Y):-atom_codes(X,A),atom_codes(Y,B),small(A,B).
small([],[]).
small([H1|T1],[H2|T2]):-H1<H2.
small([H1|T1],[H2|T2]):-H1=:=H2,small(T1,T2).
split(X,[],[],[]).
split(X,[H1|T1],[H1|Small],Big):-before(H1,X),split(X,T1,Small,Big).
split(X,[H1|T1],Small,[H1|Big]):-not(before(H1,X)),split(X,T1,Small,Big).
Please help!
In SWI-Prolog, you can use partition/4 from library(lists) and the standard order comparison (#>)/2:
?- lists:partition(#>(d),[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f].
Since the order of arguments in comparison is fixed passing the pivot in as first argument, a lambda expression (using library(yall), needs a recent version) can help to give a more intuitive reading:
?- partition([E]>>(E#<d),[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f].
Anyway, your code could be patched like this:
split(_,[],[],[]).
split(X,[H1|T1],[H1|Small],Big):-H1#<X,split(X,T1,Small,Big).
split(X,[H1|T1],Small,[H1|Big]):- \+ H1#<X,split(X,T1,Small,Big).
?- split(d,[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f] ;
false.
Your before/2 predicate succeeds if the arguments are lexicographically equivalent. For example, before(a, a) is true. That's because your 3rd clause allows equal values throughout the list until the base case finally succeeds with two empty lists.
In addition, something you haven't encountered yet evidently, is that before(X, Y) will fail if X and Y are different length atoms. For example, before(ab, abc) will fail. So your small/2 needs to take care of that case as well.
A refactoring of small/2 will fix that:
% 1st clause is fixed so unequal length atoms are handled properly
small([], _).
small([H1|_], [H2|_]) :- H1 < H2.
% 3rd clause is fixed so that equal atoms won't succeed here
small([H,H1|T1], [H,H2|T2]) :- small([H1|T1], [H2|T2]).
But... you don't need to go through all that with before/2. Prolog knows how to compare, in a sensible way, atoms (and general Prolog terms) using the #< and #> operators, as #CapelliC indicated in his answer. So your before/2 just becomes:
before(X, Y) :- X #< Y.
And you don't need small/2 at all. That's basically the second solution that #CapelliC showed in his answer.

prolog generate list of numbers from a list[x,y]

Hello I want to generate a list as following. Given a list like [x,y] I want to generate a list that is x,x,...,x : y times eg [2,3]=[2,2,2] but I cannot figure out how.
This is my implementation so far:
generate([T,1],[T]).
generate([X,S],[X|T]):-S1 is S-1,generate([X,S1],[T]).
but for some reason it fails. Can you help me?
generate([E,R], Es) :-
length(Es, R),
maplist(=(E), Es).
You said that your version fails. But in fact it does not:
?- generate([a,0], Xs).
false.
?- generate([a,1], Xs).
Xs = [a]
; false.
?- generate([a,2], Xs).
Xs = [a|a]
; false.
?- generate([a,3], Xs).
false.
It doesn't work for 0, seems to work for length 1, then, produces an incorrect solution Xs = [a|a] for length 2, and finally fails from length 3 on. [a|a] is a good hint that at someplace in your definition, lists and their elements are confused. To better distinguish them, use a variable in plural for a list, like Es which is the plural of E.
The problem is in your second clause. When you have [X|T], it means that T is a list. In the body you write generate([X,S1],[T]): by writing [T] you're now saying the second argument to generate is a list of which the only element is this list T. What you want to say is that it is simply this list T:
generate([T,1], [T]).
generate([X,S], [X|T]) :- S1 is S-1, generate([X,S1], T).

Finding all unifications in prolog

I wrote my first simple code in PROLOG:
is_beginning([], _).
is_beginning([FirstLetterB|RestWordB], [FirstLetterW|RestWordW]) :-
FirstLetterB == FirstLetterW,
is_beginning(RestWordB, RestWordW).
It is designed to find out if first argument of is_beginning is equal to the second one beginning.
Well, IMHO it can answer questions quite well, but now i wonder if there is any possibility of getting all possible answers for defined second argument.
eg. for
is_beginning(Answers, [a,b,c]);
i wish to get
[], [a], [a,b], [a,b,c]
as Answers unification, but I am getting only [] (simplest answer).
Is there any possibility of getting what I want? Maybe there is something wrong in my definition?
I already tried to use findall and forall, but it doesn't work to well for me :(
Thanks for all answers.
you are using (==)/2 when non needed (note the comment at end of documentation page). Indeed, if you change it to 'simple' unification (=)/2 your program works as you expect:
is_beginning([], _).
is_beginning([FirstLetterB|RestWordB], [FirstLetterW|RestWordW]) :-
FirstLetterB = FirstLetterW,
is_beginning(RestWordB, RestWordW).
test:
?- is_beginning(Answers, [a,b,c]).
Answers = [] ;
Answers = [a] ;
Answers = [a, b] ;
Answers = [a, b, c] ;
false.
The interpreter won't immediately return all solutions. When it returns [], press ";" to tell it to continue searching:
?- is_beginning(X, [a,b,c]).
X = [] ;
X = [a] ;
X = [a, b] ;
X = [a, b, c] ;
false.
If you need all these solutions in a Prolog list, rather than just printed out in the console, findall/3 is indeed what you're looking for:
?- findall(X, is_beginning(X, [a,b,c]), L).
L = [[], [a], [a, b], [a, b, c]].

Query for facts from list

I am new to prolog and i want to solve this problem. Suppose I have a list say
List i.e. [a,b,c]
now i have some facts say
likes(a,banana).
likes(b,orange).
likes(c,apple).
likes(d,grapes).
So if I make a query
?- my_functor(List,X).
X=[banana,orange,apple].
Thanks you.
Consider:
?- List=[a,b,c], findall(X, (member(Y, List), likes(Y, X)), Xs).
List = [a, b, c],
Xs = [banana, orange, apple].
Explanation:
findall/3 is called an 'all-solutions' predicate which seeks to find all possible values unifiable to the first argument (here, that's the variable X) to solutions for the seconds argument (here, that's the conjunction (member(Y, List), likes(Y, X))), and places all values for X into a list, bound to the third argument (here, that's Xs).
Notice that the inner expression generating the values for X is a statement that backtracks to provide different assignments for X:
?- member(Y, [a,b,c]), likes(Y, X).
Y = a,
X = banana ;
Y = b,
X = orange ;
Y = c,
X = apple ;
false.
Tested with SWI-Prolog.
Note that findall/3 also appears in GNU Prolog amongst most other implementations.

Resources