Prolog Set of and Length predicate - prolog

Im trying to work on this prolog rule which is Given a star, check whether he or she is linked with three different movies. If true, return the name of the movies, else return false.
database:
starsin(spiderman,tom_holland).
starsin(captain_america,tom_holland).
starsin(avengers,tom_holland).
starsin(parasite,kang_ho).
I tried using set of function in my rule which is:
checkStarinMovie(Star,Movie):-setof(X,starsin(X,Star),Movie).
% to the the rule write this in the query: checkStarinMovie(tom_holland,Movie).
but it would only return the list of movies that the star is in.
I want to be conditional that the star need to be in 3 movies or over. So in this case the star "kang_ho" will return false if you run in the query.
Is there anyway I could use length predicate to set a condition of the rule?

Related

Sum up data from facts

(Given a list of movies, write a PROLOG rule to add and display the total takings.)
This is my question I am basically trying to add an integer value give a list of movies from the list below. I am quite new in Prolog and I don't really understand how things work.
takings(air_force_one,315000000).
takings(american_beauty,336000000).
takings(american_pie,201700000).
takings(american_wedding,230700000).
takings(armageddon,554600000).
takings(as_good_as_it_gets,313300000).
takings(austin_powers_in_goldmember,289000000).
takings(babe,249000000).
takings(back_to_the_future,350600000).
takings(back_to_the_future_part_ii,332000000).
takings(back_to_the_future_part_iii,243700000).
takings(robots,245600000).
takings(hulk,241700000).
takings(bad_boys_ii,261900000).
The Rule I have written so far works for only one movie.
Example:
?- score([robots],Y).
Y = 245600000.
?- score([robots,hulk],Y).
false.
?- score([robots,hulk,bad_boys__ii],Y).
false.
Rule written :
score([Movies], Money):-
findall(Profit,(takings(Movies, Profit)), ListOfProfit),
sum_list(ListOfProfit, Money).
Related question asking for a recursive answer.

Checking if all elements of list are same data type (atom I guess). Prolog

I am a total beginner in Prolog. I have some custom types: bird, animal and fish. I want to pass a list to a function like so areSameType([owl, eagle, chicken]). and get a result if the whole list is type bird or animal or fish. For example:
areSameType([owl,giraffe,shark]). > false
areSameType([owl,eagle,chicken]). > true
areSameType([cat,mouse,giraffe]). > true
The data I have inserted is:
bird(owl).
bird(eagle).
bird(chicken).
animal(cat).
animal(mouse).
animal(giraffe).
fish(shark).
fish(magikarp).
fish(gyarados).
I have tried with this function:
isSameType(X,Y):- bird(X),bird(Y);animal(X),animal(Y);fish(X),fish(Y).
areSameType([H1,H2|T]):- isSameType(H1,H2), areSameType([H2,T]).
But the problem is I don't have a criteria to check if H2 is the last element of the list or maybe I got it all wrong with this logic.
There are two problems here with your areSameType/1 predicate:
there is no stop condition: in case the list is empty, or contains exactly one element, than all the items in the list have the same type; and
you need to recurse with [H2|T] (notice the pipe |, instead of the comma ,).
So we can fix this with:
areSameType([]).
areSameType([_]).
areSameType([H1,H2|T]):-
isSameType(H1,H2),
areSameType([H2|T]).
We can however use maplist/2 [swi-doc] here, and write this predicate without recursion (well no recursion in the areSameType/1 predicate itself), like:
areSameType([]).
areSameType([H1|T]) :-
maplist(isSameType(H1), T).

Prolog, print employees with same names

This is my first time using Prolog.
I have employees:
employee(eID,firstname,lastname,month,year).
I have units:
unit(uID,type,eId).
I want to make a predicate
double_name(X).
that prints the last names of the employees with the same first name in the unit X.
I am doing something like this :
double_name(X) :-
unit(X,_,_eID),
employee(_eID,_firstname,_,_,_),
_name = _firstname,
employee(_,_name,_lastname,_,_),
write(_lastname).
But it prints all the employees in the unit.
How can i print only the employees with the same name ?
unit(unit_01,type,1).
unit(unit_01,type,2).
unit(unit_01,type,3).
employee(1,mary,smith,6,1992).
employee(2,fred,jones,1,1990).
employee(3,mary,cobbler,2,1995).
double_name(Unit) :-
unit(Unit,_,Eid_1),
employee(Eid_1,Firstname,Lastname_1,_,_),
unit(Unit,_,Eid_2),
Eid_1 \= Eid_2,
employee(Eid_2,Firstname,Lastname_2,_,_),
write(Firstname),write(","),write(Lastname_1),nl,
write(Firstname),write(","),write(Lastname_2).
Variables in Prolog typically start with an upper case letter, but starting them with and underscore is allowed, but not typical.
In double_name/2 the predicates like
unit(Unit,_,Eid_1)
employee(Eid_1,Firstname,Lastname_1,_,_)
are used to load the values from the facts into variables while pattern matching (via unification) that the bound variables match with the fact.
To ensure that a person is not compared with themselves.
Eid_1 \= Eid_2
and to make sure that two people have the same first name the same variable is used: Firstname.
The write/1 and nl/0 predicates just write the result to the screen.
Example:
?- double_name(unit_01).
mary,smith
mary,cobbler
true ;
mary,cobbler
mary,smith
true ;
false.
Notice that the correct answer is duplicated. This can be resolved.
See: Prolog check if first element in lists are not equal and second item in list is equal
and look at the use of normalize/4 and setof/3 in my answer
which I leave as an exercise for you.

Prolog bagof, setof, findall predicates

How do I query database facts with 3 or more attributes in Prolog using bagof, setof. An example I have a defined a database students(name, grade,sport,gender). I want find a list of students that play a particular sport, say cricket. My current query
sport_list(L):-
bagof(S,N^G^D^students(N,G,S,D),L),
S = cricket.
student(patash,5,rugby,male).
student(naomi,3,netball,female).
student(lepo,6,_,male).
student(diamal,4,cricket,male).
student(bonga,5,chess,female).
student(imi,6,cricket,male).
student(ayanda,3,_,female).
You could model your knowledge base such that the third argument is none for unathletic students instead of _:
student(lepo,6,none,male).
student(ayanda,3,none,female).
Then you can define a predicate that describes atheletic students as being those who do not have none as sport:
athletic(S) :-
dif(X,none),
student(S,_,X,_).
Subsequently use athletic/1 in the single goal of sport_list/1:
sport_list(L):-
bagof(S,athletic(S),L).
That yields the desired result:
?- sport_list(L).
L = [patash,naomi,diamal,bonga,imi]

Recursively (?) compose LINQ predicates into a single predicate

(EDIT: I have asked the wrong question. The real problem I'm having is over at Compose LINQ-to-SQL predicates into a single predicate - but this one got some good answers so I've left it up!)
Given the following search text:
"keyword1 keyword2 keyword3 ... keywordN"
I want to end up with the following SQL:
SELECT [columns] FROM Customer
WHERE
(Customer.Forenames LIKE '%keyword1%' OR Customer.Surname LIKE '%keyword1%')
AND
(Customer.Forenames LIKE '%keyword2%' OR Customer.Surname LIKE '%keyword2%')
AND
(Customer.Forenames LIKE '%keyword3%' OR Customer.Surname LIKE '%keyword3%')
AND
...
AND
(Customer.Forenames LIKE '%keywordN%' OR Customer.Surname LIKE '%keywordN%')
Effectively, we're splitting the search text on spaces, trimming each token, constructing a multi-part OR clause based on each token, and then AND'ing the clauses together.
I'm doing this in Linq-to-SQL, and I have no idea how to dynamically compose a predicate based on an arbitrarily-long list of subpredicates. For a known number of clauses, it's easy to compose the predicates manually:
dataContext.Customers.Where(
(Customer.Forenames.Contains("keyword1") || Customer.Surname.Contains("keyword1")
&&
(Customer.Forenames.Contains("keyword2") || Customer.Surname.Contains("keyword2")
&&
(Customer.Forenames.Contains("keyword3") || Customer.Surname.Contains("keyword3")
);
but I want to handle an arbitrary list of search terms. I got as far as
Func<Customer, bool> predicate = /* predicate */;
foreach(var token in tokens) {
predicate = (customer
=> predicate(customer)
&&
(customer.Forenames.Contains(token) || customer.Surname.Contains(token));
}
That produces a StackOverflowException - presumably because the predicate() on the RHS of the assignment isn't actually evaluated until runtime, at which point it ends up calling itself... or something.
In short, I need a technique that, given two predicates, will return a single predicate composing the two source predicates with a supplied operator, but restricted to the operators explicitly supported by Linq-to-SQL. Any ideas?
I would suggest another technique
you can do:
var query = dataContext.Customers;
and then, inside a cycle do
foreach(string keyword in keywordlist)
{
query = query.Where(Customer.Forenames.Contains(keyword) || Customer.Surname.Contains(keyword));
}
If you want a more succinct and declarative way of writing this, you could also use Aggregate extension method instead of foreach loop and mutable variable:
var query = keywordlist.Aggregate(dataContext.Customers, (q, keyword) =>
q.Where(Customer.Forenames.Contains(keyword) ||
Customer.Surname.Contains(keyword));
This takes dataContext.Customers as the initial state and then updates this state (query) for every keyword in the list using the given aggregation function (which just calls Where as Gnomo suggests.

Resources