如何在序言中分配 return 变量?

How do I assign return variable in 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 调用的结果值附加到结果,以便 return 累积结果? 我尝试使用 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

提前致谢:)

我想你想要:

?- 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 发布的所有推文。

首先,几点说明:

  • 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.

这里没有理由使用递归。您只需使用 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).

所以 tweets([fred],Ts) 产生预期的 Ts = [tweet1, tweet5, tweet2, tweet7, tweet8].

但如果作者列表是一个变量,它就会失败。如果 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]