我对Prolog完全陌生,所以我可能真的不在这里。在过去的一周里,我正在努力解决以下问题:
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).
如果我用单个变量调用,那么只有一个递归调用,我得到的结果是:
?- tweets([fred], R).
R = [tweet2, tweet7, tweet8].
但我很难理解如何将findTweets调用的Result值附加到Result以返回累积结果?我试着使用append
函数,但没有成功。。。例如:
tweets([], _).
tweets([Name|Names], Result) :-
findTweets(Name, Tweets),
append(Tweets, Result, Temp),
Result is Temp,
tweets(Names, Result).
但我得到了这个错误:
?- 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
提前感谢:(
首先,请注意:
is
仅用于数字算术计算。你不能在列表中使用它,你会得到一个错误- 你永远不能"重新分配";Prolog中的变量。如果你想要一个新术语的名称,你总是需要使用一个新的变量
除此之外,您使用append
是正确的。我的解决方案与你的接近,只需要重新安排一下:
persons_tweets([], []).
persons_tweets([Person | Persons], AllTweets) :-
person_tweets(Person, ThisPersonTweets),
persons_tweets(Persons, OtherPersonsTweets),
append(ThisPersonTweets, OtherPersonsTweets, AllTweets).
我将你的findTweets
重命名为person_tweets
,以更清楚地表明这是一个人和一组推特之间的关系。类似地,persons_tweets
是个人集合(列表(和推特之间的关系。
示例:
?- persons_tweets([fred, anne], Tweets).
Tweets = [tweet2, tweet7, tweet8, tweet1, tweet5].
请注意,非递归情况为persons_tweets([], []).
。此处不能使用匿名变量_
。如果你有一个空的人列表,你真的想有一个推文的空列表,而不仅仅是任何推文。例如,这应该会失败,但使用您的版本,它会成功:
?- persons_tweets([], [some_tweet]).
false.
我想你想要:
?- 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].
这列出了Names在推特上发布的所有推文。
这里没有理由使用递归。只需使用findall/3
即可完成。试试这样的东西:
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).
因此CCD_ 10产生了预期的CCD_。
但是,如果作者名单是一个变量,它就会失败。如果prolog谓词的行为对称,那就太好了。因此,让我们在这里添加几个助手:
这允许用户将单个名称指定为原子(可能是常见的用例(:
tweets( P , Ts ) :- atom(P) , ! , tweets([P],Ts) .
这允许用户将人员列表作为未绑定变量,从而检索所有推文(并生成作者列表(:
tweets( Ps , Ts ) :- var(Ps) , ! , setof(P,T^tweet(P,T),Ps) , tweets(Ps,Ts) .
[注意:setof/3
调用中的表达式,T^tweet(P,T)
是一个存在限定词。它告诉setof/3
在确定集合时忽略T
的值,因此您得到的是P
的不同集合,而不是[P,T]
对的不同集合。
如果你把它们放在一起,
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).
你可以说tweets(anne,Ts)
,然后得到预期的Ts = [tweet1, tweet5]
。
同样,你可以说tweets(Ps,Ts)
,然后得到
Ps = [anne, fred],
Ts = [tweet1, tweet5, tweet2, tweet7, tweet8]