【问题标题】:Use cut in Prolog to define a once_member/2 function在 Prolog 中使用 cut 定义一个 once_member/2 函数
【发布时间】:2011-11-26 23:36:43
【问题描述】:

免责声明:这是在我自己的时间完成的非正式且未经评估的课程。我自己试过了,失败了,现在正在寻找一些指导。

我正在尝试实现 member/2 函数的一个版本,它只会返回列表的成员一次。

例如:

| ?- member(X, [1,2,3,1]).
X = 1 ? ;
X = 2 ? ;
X = 3 ? ;
X = 1 ? ;

我希望每个数字最多只打印一次。

| ?- once_member(X, [1,2,3,1]).
X = 1 ? ;
X = 2 ? ;
X = 3 ? ;
no

我们被告知要使用剪辑“!”来执行此操作操作员,但我已经查看了我的课程笔记,以了解 cut 和更多在线内容,但仍然无法在我的脑海中点击!

到目前为止,我已经设法得到:

once_member(E, [E | L]) :- !.
once_member(E, [_, L]) :-
    once_member(E, L).

返回 1,然后什么都没有,我觉得我的剪辑位置错误,并且阻止了每场可能的比赛的回溯,但我真的不确定下一步该去哪里。

我查看了我的课程笔记以及:http://www.cs.ubbcluj.ro/~csatol/log_funk/prolog/slides/5-cuts.pdfProgramming in Prolog (Google Books)

关于如何在逻辑上应用剪辑的指导将是最有用的,但答案可能会帮助我自己弄清楚。

我们还被告知要使用另一种方法,该方法使用'\+' 否定失败,但希望一旦 cut 对我来说这可能会更简单?

【问题讨论】:

    标签: prolog prolog-cut


    【解决方案1】:

    删除多余的答案保持纯净!

    我们根据if_/3 and (=)/3定义memberd/2

    成员(X,[E|Es]):- if_(X = E, true, memberd(X, Es))。

    尤其是元谓词,有时不同的参数顺序可能会派上用场:

    list_memberd(Es, X) :-
       memberd(X, Es).
    

    示例查询:

    ?- memberd(X, [1,2,3,1]).
    X = 1 ;
    X = 2 ;
    X = 3 ;
    false.
    

    【讨论】:

    • 现在只需要效率,避免创建不必要的选择点!
    • 那将是(=)/3内的CP。
    • 所有相关案例都会被淘汰。如果没有确定的方法来产生正确的答案,它也不会被消除。也就是说=(X,Y,R) 会成功两次。
    • =(X,Y,R) 成功了两次。一次使用X = Y,一次使用dif(X, Y)
    【解决方案2】:

    有cut的解决办法……一开始听起来挺麻烦的。

    假设第一个参数将被实例化,解决方案很简单:

    once_member(X,L):-
        member(X,L),!.
    

    但是如果第一个参数没有被实例化,这将不会有你想要的行为。
    如果我们知道列表元素的域(例如 1 到 42 之间的数字),我们可以实例化第一个参数:

    once_member(X,L):-
        between(1,42,X),
        member_(X,L).
    
    member_(X,L):-
        member(X,L),!.
    

    但这是非常低效的

    在这一点上,我开始相信不可能只用剪切(假设我们不使用 + 或 list_to_set/2
    等一下!

    如果我们可以实现一个谓词(如 swi-prolog 的 list_to_set/2),它会接受一个列表并生成一个列表,其中所有重复元素都被删除,我们可以简单地使用普通成员/2 而不会得到重复的结果。试试看吧,我想你自己会写的。

    --------剧透------------

        one_member(X,L):-
            list_to_set(L,S),
            member(X,S).
    
        list_to_set([],[]).
        list_to_set([H|T],[H|S]):-
            remove_all(H,T,TT),
            list_to_set(TT,S).
    
    %remove_all(X,L,S): S is L if we remove all instances of X
        remove_all(_,[],[]).
        remove_all(X,[X|T],TT):-
            remove_all(X,T,TT),!.
        remove_all(X,[H|T],[H|TT]):-
            remove_all(X,T,TT).
    

    如您所见,我们必须在 remove_all/3 中使用 cut ,否则第三个子句可以与 remove_all(X,[X|_],_) 匹配,因为我们没有指定 H 与 X 不同。我相信 not 的解决方案是微不足道的。

    顺便说一句,带有 not 的解决方案比带有 cut 的解决方案更具声明性;我们使用的剪切通常称为红色剪切,因为它会改变程序的行为。还有其他问题;请注意,即使有删减,remove_all(1,[1,2],[1,2]) 也会成功。

    另一方面,对一个条件进行两次检查效率不高。因此,最佳方案是使用 if-then-else 结构(但我假设您也不允许使用它;它的实现可以通过剪切来完成)。

    另一方面,not 还有另一个更简单的实现:您不仅应该检查 X 是否是列表的成员,还应该检查您以前是否遇到过它;所以你需要一个蓄能器:

    -------------剧透--------

    once_member(X,L):-
        once_member(X,L,[]).
    once_member(X,[X|_T],A):-
        \+once_member(X,A).
    once_member(X,[H|T],A):-
        once_member(X,T,[H|A]).
    

    【讨论】:

      【解决方案3】:
      once_member(X, Xs) :-
         sort(Xs, Ys),
         member(X, Ys).
      

      与发布的几乎所有其他解决方案一样,这有一些异常情况。

      ?- X = 1, once_member(X, [A,B]).
      X = A, A = 1 ;
      X = B, B = 1.
      
      ?- X = 1, once_member(X, [A,A]).
      X = A, A = 1.
      

      【讨论】:

        【解决方案4】:

        这是一种在 once_member/2 的定义中与经典的 member/2 谓词一起使用切割的方法:

        once_member(X,[H|T]) :-
            member(H,T),
            !,
            once_member(X,T).
        once_member(H,[H|_]).
        once_member(X,[_|T]) :-
            once_member(X,T).
        

        应用于上面的例子:

        ?- once_member(X,[1,2,3,1]).
        
        X = 2 ;
        
        X = 3 ;
        
        X = 1 ;
        no
        

        注意:尽管出现奇怪的三个子句定义,但 once_member/2 是符合最后调用/尾递归优化条件的,因为在它的第一次自调用。

        【讨论】:

        • 我将其标记为正确,因为它似乎与他们所追求的最匹配(通过阅读问题)。然而,其他答案似乎也非常好,尤其是提供了大量有用提示和信息的 thanosQR。谢谢大家!
        • 事实上,我的一个测试有这个,只是缺少旧的 member/2 谓词,因此我认为为什么会出现异常。
        猜你喜欢
        • 2013-01-10
        • 1970-01-01
        • 2015-12-10
        • 2013-08-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多