【问题标题】:Prolog (Sicstus) - nonmember and setof issuesProlog (Sicstus) - 非成员和 setof 问题
【发布时间】:2017-01-08 04:56:13
【问题描述】:

鉴于以下事实:

route(TubeLine, ListOfStations).

route(green, [a,b,c,d,e,f]).
route(blue, [g,b,c,h,i,j]).
...

我需要找到所有没有任何公共站点的地铁线路对,生成以下内容:

| ?- disjointed_lines(Ls).
Ls = [(yellow,blue),(yellow,green),(yellow,red),(yellow,silver)] ? ;
no

我想出了下面的答案,但是它不仅给了我不正确的答案,而且也没有应用我的 X^ 条件 - 即它仍然单独打印每个站列表成员的结果:

disjointed_lines(Ls) :- 
                        route(W, Stations1),
                        route(Z, Stations2),
                        setof(
                        (W,Z),X^
                        (member(X, Stations1),nonmember(X, Stations2)),
                         Ls).

这是定义产生的输出:

| ?- disjointed_lines(L).
L = [(green,green)] ? ;
L = [(green,blue)] ? ;
L = [(green,silver)] ? ;
...

我认为我与会员资格相关的逻辑是不正确的,但是我无法弄清楚哪里出了问题。谁能看到我哪里失败了?

我还按照建议here 阅读了关于结果收集的 Learn Prolog Now 第 11 章,但似乎我仍然无法正确使用 ^ 运算符。任何帮助将不胜感激!


更新:

根据用户 CapelliC 的建议,我将代码更改为以下内容:

disjointed_lines(Ls) :- 
                        setof(
                        (W,Z),(Stations1, Stations2)^
                        ((route(W, Stations1),
                        route(Z, Stations2),notMembers(Stations1,Stations2))),
                         Ls).

notMembers([],_).
notMembers([H|T],L):- notMembers(T,L), nonmember(H,L).

然而,下面给出了 (X,Y) 和 (Y,X) 的重复项,但下一步将在单独的规则中删除它们。感谢您的帮助!

【问题讨论】:

    标签: prolog prolog-setof


    【解决方案1】:

    我认为你应该把 route/2 调用放在 setof' 目标中,并且更清楚地表达不相交,这样你就可以单独测试它。关于^ 运算符,它要求一个变量在目标范围内普遍量化。也许像 bagof/3 手册页上的简明解释会有所帮助...

    disjointed_lines(Ls) :- 
      setof((W,Z), Stations1^Stations2^(
        route(W, Stations1),
        route(Z, Stations2),
        disjoint(Stations1, Stations2)
      ), Ls).
    
    disjoint(Stations1, Stations2) :-
      ... % could be easy as intersection(Stations1, Stations2, [])
          % or something more efficient: early fail at first shared 'station'
    

    【讨论】:

    • 非常感谢!我根据您的建议添加了以下定义来解决问题:notMembers([],_)。非成员([H|T],L):- 非成员(T,L),非成员(H,L)。完整的解决方案给了我 [(X,Y),(Y,X)] 的重复项,所以删除这些重复项对我来说是最后一步:)
    • 要删除重复项,您可以在setof 调用中使用W @< Z 作为附加目标。
    【解决方案2】:

    如果你创建一个辅助谓词来表达你感兴趣的关系,setof/3 会更容易使用:

    disjoint_routes(W, Z) :-
        route(W, Stations1),
        route(Z, Stations2),
        disjoint(Stations1, Stations2).
    

    有了这个,disjointed_lines/1 的定义变得更短更简单了并且不再需要任何^ 操作符

    disjointed_lines(Ls) :-
        setof((W, Z), disjoint_routes(W, Z), Ls).
    

    setof/3 的结果中不需要的变量会自动隐藏在辅助谓词定义中。

    【讨论】:

    • 非常感谢,这是一个很棒的提示!如果我对 ^ 有任何问题,我一定会使用它 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多