I want to define a predicate suffix (S,L) which holds if S is a list which is a suffix of
list L. For exemple:
?− suffix([a,b,c],[b,c]).
true.
?− suffix([a,b,c],[b,a]).
false.
I tried using suffix(S,L):- append(_,S,L). but this won't work with my examples, shown above.
This works (see https://swish.swi-prolog.org/p/gMgNaCKQ.pl for a working example):
suffix(L,S) :- append(_,S,L).
This also works (see https://swish.swi-prolog.org/p/XqCXArvz.pl for a working example):
suffix( L , L ) . % every list is a suffix of itself, with the empty list [] as its prefix
suffix( [_|L] , S ) :- suffix(L,S) . % otherwise, pop the list and try again.
I'm totally new to Prolog so I might be really off here.
I'm trying to solve the following problem for the past week:
tweeted(anne, tweet1).
tweeted(anne, tweet5).
tweeted(fred, tweet2).
tweeted(fred, tweet7).
tweeted(fred, tweet8).
findTweets(Name, TweetsByName) :- findall(X, tweeted(Name, X), TweetsByName).
tweets([], _).
tweets([Name|Names], Result) :-
findTweets(Name, Result),
/* how do I append Result to Result ? */
tweets(Names, Result).
If I call with single variable, there's only one recursion call and I get result:
?- tweets([fred], R).
R = [tweet2, tweet7, tweet8].
But I'm struggling to understand how can I append Result value from findTweets call to Result in order to return accumulative result?
I tried using append function but I had no luck...
for example:
tweets([], _).
tweets([Name|Names], Result) :-
findTweets(Name, Tweets),
append(Tweets, Result, Temp),
Result is Temp,
tweets(Names, Result).
But I get this error:
?- tweets([fred], R).
ERROR: Type error: `character' expected, found `tweet2' (an atom)
ERROR: In:
ERROR: [11] _25712 is [tweet2,tweet7|...]
ERROR: [10] tweets([fred],_25752) at /home/kimchi/git-repos/bbk/Programming-Language-Paradigms/logic-programming-Pavel-Durov/relationships.pl:33
ERROR: [9] toplevel_call(user:user: ...) at /snap/swi-prolog/43/usr/lib/swipl/boot/toplevel.pl:1117
Thanks in advance :)
First, a few notes:
is is only for arithmetic computations on numbers. You cannot use it on lists, you will get an error.
You can never "re-assign" variables in Prolog. You always need to use a new variable if you want to want a name for a new term.
Apart from that, you are on the right track with append. My solution is close to yours, it just needed to be rearranged a bit:
persons_tweets([], []).
persons_tweets([Person | Persons], AllTweets) :-
person_tweets(Person, ThisPersonTweets),
persons_tweets(Persons, OtherPersonsTweets),
append(ThisPersonTweets, OtherPersonsTweets, AllTweets).
I renamed your findTweets to person_tweets to make clearer that it is a relation between one person and a collection of tweets. Similarly, persons_tweets is a relation between a collection (list) of persons and tweets.
Example:
?- persons_tweets([fred, anne], Tweets).
Tweets = [tweet2, tweet7, tweet8, tweet1, tweet5].
Note that the non-recursive case is persons_tweets([], []). You cannot use the anonymous variable _ here. If you have an empty list of persons, you really want to have an empty list of tweets, not just any tweets. For instance, this should fail, but with your version it would succeed:
?- persons_tweets([], [some_tweet]).
false.
I think you want:
?- Names = [fred], findall(Tweet, (member(Name, Names), tweeted(Name, Tweet)), Tweets).
Names = [fred],
Tweets = [tweet2,tweet7,tweet8].
?- Names = [anne, fred], findall(Tweet, (member(Name, Names), tweeted(Name, Tweet)), Tweets).
Names = [anne,fred],
Tweets = [tweet1,tweet5,tweet2,tweet7,tweet8].
This is listing all the tweets that were tweeted by the Names.
There's no reason to use recursion here. You can do it just with findall/3. Try something like this:
tweet( anne , tweet1 ).
tweet( anne , tweet5 ).
tweet( fred , tweet2 ).
tweet( fred , tweet7 ).
tweet( fred , tweet8 ).
tweets( Ps , Ts ) :- findall(T,desired_tweet(Ps,T),Ts).
desired_tweet(Ps,T) :- tweet(P,T), member(P,Ps).
So tweets([fred],Ts) yields the expected Ts = [tweet1, tweet5, tweet2, tweet7, tweet8].
But it fails horribly if the list of authors is a variable. And it's nice if prolog predicates behave symmetrically. So lets add a couple of helpers here:
This lets the user specify a single name as an atom (a likely common use case):
tweets( P , Ts ) :- atom(P) , ! , tweets([P],Ts) .
And this lets the user leave the persons list as an unbound variable, which will results in retrieving all the tweets (and generating a list of authors):
tweets( Ps , Ts ) :- var(Ps) , ! , setof(P,T^tweet(P,T),Ps) , tweets(Ps,Ts) .
[Note: the expression in the setof/3 invocation, T^tweet(P,T) is an existential quantifier. It tells setof/3 to ignore the values of T in determining the set, so you get the distinct set of P rather than the distinct set of [P,T] pairs.
If you put it all together,
tweet( anne , tweet1 ).
tweet( anne , tweet5 ).
tweet( fred , tweet2 ).
tweet( fred , tweet7 ).
tweet( fred , tweet8 ).
tweets( P , Ts ) :- atom(P) , ! , tweets([P],Ts) .
tweets( Ps , Ts ) :- var(Ps) , ! , setof(P,T^tweet(P,T),Ps) , tweets(Ps,Ts) .
tweets( Ps , Ts ) :- findall(T,desired_tweet(Ps,T),Ts).
desired_tweet(Ps,T) :- tweet(P,T), member(P,Ps).
You can says tweets(anne,Ts) and get the expected Ts = [tweet1, tweet5].
And, similarly, you can say tweets(Ps,Ts) and get
Ps = [anne, fred],
Ts = [tweet1, tweet5, tweet2, tweet7, tweet8]
I am beginner in Prolog.I have my custom types bird,fish,animal. So the problem is I want to pass function like firstLast([owl,chicken,cat,eagle]) and get result true because first and last are same data type. For another example:
firstLast([dog,owl,shark,eagle,cat]).
> true
firstLast([shark,dog,owl,mouse]).
> false
This is my base data:
bird(eagle).
bird(chicken).
animal(cat).
animal(mouse).
animal(dog).
fish(shark).
fish(wheal).
fish(goldfish).
isSameType(X,Y):-
( bird(X),bird(Y)
; animal(X),animal(Y)
; fish(X),fish(Y)
).
This should work, using last/2:
firstLast([X|Tail]):-
last(Tail, Y),
isSameType(X,Y).
Completely new to prolog. Interesting journey so far in trying to change how I think, so appreciate any help here.
I am trying to assert facts for a pre-defined set of names. For example, assume I have a a set of people [alice, bob, ...] in one file. I would like to assert facts about these folks in other files, but want to make sure that these folks exist and that is checked when the facts are loaded/compiled(?).
For example, assume I don't have 'chuck' in the list and I make an assertion:
user: swipl app.pl
?- full_name(chuck, "Charlie Steel").
should result in an error.
What is the best way I can do this?
So, here's the code I came up with:
person(deborah).
person(tony).
read_my_file(Filename) :-
open(Filename, read, In),
read_my_file1(In),
close(In).
read_my_file1(In) :-
read(In, Term),
( Term == end_of_file
-> true
; assert_or_abort(Term),
read_my_file1(In)
).
assert_or_abort(Term) :-
( full_name(Person, Name) = Term
-> ( person(Person)
-> assertz(full_name(Person, Name))
; format(user, '~w is not a person I recognize~n', [Person])
)
; format(user, '~w is not a term I know how to parse~n', [Term])
).
The trick here is using read/2 to obtain a Prolog term from the stream, and then doing some deterministic tests of it, hence the nested conditional structure inside assert_or_abort/1. Supposing you have an input file that looks like this:
full_name(deborah, 'Deborah Ismyname').
full_name(chuck, 'Charlie Steel').
full_name(this, has, too, many, arguments).
squant.
You get this output:
?- read_my_file('foo.txt').
chuck is not a person I recognize
full_name(this,has,too,many,arguments) is not a term I know how to parse
squant is not a term I know how to parse
true.
?- full_name(X,Y).
X = deborah,
Y = 'Deborah Ismyname'.
Given this program, why am I forced to define every atom in the predicate, even if they're anonymous. Why is it that undefined variables in a dict predicate aren't thought of as anonymous?
funt2(X) :-
X = point{x:5, y:6}.
evalfunt(point{x:5, y : 6}) :-
write('hello world!').
evalfunt(point{x:_, y : _} ) :-
write('GoodBye world!').
Why can't I just say
evalfunt(point{x:5}) :-
write('GoodBye world!').
^that won't match, by the way.
I may as well just use a structure if I have to define every possible value in the dict to use dicts.
What's the motivation here? Can I do something to make my predicate terse? I'm trying to define a dict with 30 variables and this is a huge roadblock. It's going to increase my program size by a magnitude if I'm forced to define each variables (anonymous or not).
Dict is just a complex data type, like tuple, which has data AND structure. If you have, for example two facts:
fact(point{x:5, y:6}).
fact(point{x:5}).
Then the query
fact(point{x:_}).
will match the second one, but not the first one.
And the query
fact(point{x:_, y:_}).
Will match the first one, but not the second.
Now, if you want to match facts of the form fact(point{x:_, y:_, z:_}) only by one specific field, you can always write a helper rule:
matchByX(X, P) :- fact(P), P=point{x:X, y:_, z:_}.
So having facts:
fact(point{x:5, y:6, z:1}).
fact(point{x:1, y:2, z:3}).
fact(point{x:2, y:65, z:4}).
and quering
matchByX(1, P).
will return:
P = point{x:1, y:2, z:3}
UPDATE:
Moreover, in SWI-Prolog 7 version the field names can be matched as well, so it can be written in much more generic way, even for facts with different structures:
fact(point{x:5, y:6, z:1}).
fact(point{x:1, y:2}).
fact(point{x:2}).
fact(point{x:2, y:2}).
matchByField(F, X, P) :- fact(P), P.F = X.
So query:
?- matchByField(x, 2, P).
P = point{x:2} ;
P = point{x:2, y:2}.
I was able to accomplish what I needed by doing the following
checkiffive(Y) :-
get_dict(x, Y, V), V=5.
You need to use the built in methods for unifying values from a dict.
Described in chapter 5.4 of the SWI prolog reference
http://www.swi-prolog.org/download/devel/doc/SWI-Prolog-7.1.16.pdf