如何在prolog中分配返回变量



我对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]

最新更新