【问题标题】:Correct use of findall/3, especially the last result argument正确使用 findall/3,尤其是最后一个结果参数
【发布时间】:2014-06-18 15:17:44
【问题描述】:

我是 Prolog 的初学者,我正在处理一个在你看来可能很愚蠢的问题,但我真的不明白我做错了什么!好的,我有这个文件 fruits.pl,里面有这样的东西:

fruit(apple,small,sweet).
fruit(lemon,small,nosweet).
fruit(melon,big,sweet).

我已经(在该文件中创建了一个并存(X,Y)原子,用于检查两个水果是否可以放在一个盘子中。它工作正常!但现在我无法创建一个需要的建议(X)作为一个水果的参数,并返回一个可以放在同一个盘子里的水果列表。 问题是我正在尝试制作类似的东西

suggest(X) :- findall(Y,fruit(Y,_,_), List), coexist(X,Y).

你怎么看?每次我尝试在 swi prolog 中运行它时,都会出现警告“单例变量”,当我按下时

suggest(apple).

然后它说假.. 对不起我的英语:/

【问题讨论】:

    标签: variables prolog singleton prolog-setof prolog-findall


    【解决方案1】:

    Prolog 中的谓词不返回任何内容。您的目标是否满足,您可以将其解释为返回truefalse

    您的谓词suggest(X) 应该包含另一个参数,该参数将绑定到与X 一起出现的水果列表。一个选项是:suggest(X, List),它描述了以下关系:List 表示与X 一起出现的所有水果。然后,你可以问:

    ?- suggest(apple, List).
    List = [pear, cherry].
    

    目标findall(Y, ... , ...) 在内部使用Y 变量,在满足目标后Y 仍然未绑定。因此,您应该将coexist(X,Y) 移动到findall/3 的第二个参数中,这是以所有可能方式满足的目标。以下规则仅在 X 被实例化 (suggest(+X, -List)) 时有效。

    suggest(X, List) :- findall(Y, (fruit(Y,_,_), coexist(X, Y)), List).
    

    你可以这样解读:“List代表所有与X共存的水果Y”。

    【讨论】:

    • 如果我想限制水果的数量,取决于哪个大哪个小?我的意思是,如果我选择的水果小,我建议盘子里最多 2 个水果,如果水果大,我最多 3 个。
    • 要限制List 的长度,您可以在规则中添加以下两个目标:between(1, 3, Len), length(List, Len)
    • 添加这个事实:limit(small,2).limit(big,3). 和规则 suggest(X, List) :- findall(Y, (fruit(Y,_,_), coexist(X, Y)), List), X = fruit(_, Size, _), limit(Size, N), between(0, N, Len), length(List, Len).
    • @eLsA:你现在完全改变了你想要的。如果这很重要,请使用一个新问题。
    • 抱歉,搞错了:X = fruit(_, Size, _) 而不是fruit(X, Size, _)
    【解决方案2】:

    当您尝试在 Prolog 中定义谓词时,首先假装您已经编写了该谓词并开始想象您将如何使用它。也就是说,您想提出什么问题。

    在我看来,coexist/2 似乎已经描述了你想要什么。顺便说一句,may_coexist/2 可能是一个更具描述性的名称。为什么要将它放在单独的列表中?为什么要使用fruit/3?但是为了这个问题,让我们假设这是有道理的。所以基本上你现在有一个关系fruit_compatible/2

    fruit_compatible(F, G) :-
       fruit(F, _, _),
       may_coexist(F, G),
       fruit(G, _, _).  % maybe you want to add this?
    

    现在,假设您也想要这个列表。所以你会有一个关系fruit_suggestions/2。怎么用?

    ?- fruit_suggestions(apple, L).
    L = [cherry, pear].
    

    或者...应该是L = [pear, cherry]?还是两者兼有?

    ?- fruit_suggestions(lemon, L).
    L = [orange].
    

    所以每次我想要一个建议时,我都必须想一个水果。一直在想:应该是什么水果?幸运的是,Prolog 中有一种要求不高的方法:只需使用变量而不是水果!现在我们应该立即获得所有建议!

    ?- fruit_suggestions(F, L).
    F = apple, L = [cherry, pear] ;
    F = lemon, L = [orange] ;
    F = cromulon, L = [embiggy, mushfruit].
    

    所以我们需要实现它,使它的行为方式。 findall/3 单独不能解决这个问题。手动实现它绝非易事。但是有setof/3 以这种方式处理变量。许多微小的细节设计决策已经做出,例如列表将按升序排序。

    fruit_suggestions(F, L) :-
       setof(G, fruit_compatible(F, G), L).
    

    编辑:由于下面的讨论,这将是一个也允许空列表的解决方案。请注意,这听起来微不足道,但事实并非如此。要看到这一点,请考虑以下查询:

    ?- fruit_suggestions(F, []).
    

    这是什么意思? F 应该是什么?还有那些根本不是水果的东西?在这种情况下,我们将不得不为一切提供解决方案。喜欢F = badger ; F = 42 ; ...。很可能这没有多大意义。可能是那些与一切不相容的果实。为此,我们需要添加一条新规则:

    fruit_suggestions(F, []) :-
       setof(t,X^Y^fruit(F,X,Y),_),
       \+ fruit_compatible(F, _).
    fruit_suggestions(F, L) :-
       setof(G, fruit_compatible(F, G), L).
    

    【讨论】:

    • 此解决方案可能存在一个问题:如果无法满足目标,setof/3 将失败。因此,如果没有与给定的F 兼容的水果,则结果将为false,而不是L=[]。当然,添加剪切运算符和第二条规则很容易fruit_suggestions(_,[]).
    • 在描述谓词时,我们应该对参数使用实例化模式。您的解决方案最适合suggest(?Fruit,?List),但findall/3 可能更适合suggest(+Fruit,-List)
    • @Tudorberiariu:你如何控制你建议的模式/实例化模式?
    • [] 与否的问题与是否一致的问题是分开的。在您的解决方案中suggest(X, List) 给出了一个很长的列表。必须防止这种情况发生:无论是通过错误还是通过更好的实现。
    • @TudorBerariu:在这种情况下,suggest/2 不是关系。这就是重点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-18
    • 2020-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-14
    相关资源
    最近更新 更多