将成员谓词实现为单行

时间:2009-11-16 19:11:15

标签: list prolog dcg

面试问题!

这就是你通常在Prolog中定义member关系的方法:

member(X, [X|_]).        % member(X, [Head|Tail]) is true if X = Head 
                         % that is, if X is the head of the list
member(X, [_|Tail]) :-   % or if X is a member of Tail,
  member(X, Tail).       % ie. if member(X, Tail) is true.

仅使用一个规则定义它。

4 个答案:

答案 0 :(得分:36)

  1. 解决方案:

    member(X, [Y|T]) :- X = Y; member(X, T).
    
  2. 演示:

    ?- member(a, []).
    fail.
    ?- member(a, [a]).
    true ;
    fail.
    ?- member(a, [b]).
    fail.
    ?- member(a, [1, 2, 3, a, 5, 6, a]).
    true ;
    true ;
    fail.
    
  3. 工作原理:

    • 我们正在寻找第二个参数X中出现的第一个参数[Y|T]
    • 假设第二个参数是一个列表。 Y匹配其头部,T匹配尾部。
    • 因此,谓词对于空列表失败(应该如此)。
    • 如果X = Y(即X可以与Y统一),那么我们会在列表中找到X。否则(;)我们会测试X是否在尾部。
  4. 说明:

    • 感谢humble coffee指出使用=(统一)会产生比使用==更灵活的代码(测试相等性)。
    • 此代码也可用于枚举给定列表的元素:

      ?- member(X, [a, b]).
      X = a ;
      X = b ;
      fail.
      
    • 它可用于“枚举”包含给定元素的所有列表:

      ?- member(a, X).
      X = [a|_G246] ;
      X = [_G245, a|_G249] ;
      X = [_G245, _G248, a|_G252] ;
      ...
      
    • 在上面的代码中用=替换==会降低灵活性:它会在member(X, [a])上立即失败并导致member(a, X)上的堆栈溢出(使用SWI-Prolog版本5.6.57测试)。

答案 1 :(得分:20)

由于你没有指定我们允许使用的其他谓词,我将尝试作弊。 :P

member(X, L) :- append(_, [X|_], L).

答案 2 :(得分:7)

newmember(X, Xs) :-
   phrase(( ..., [X] ),Xs, _).

使用

... --> [] | [_], ... .

实际上,以下定义还确保Xs是一个列表:

member_oflist(X, Xs) :-
   phrase(( ..., [X], ... ), Xs).

致谢

...的上述定义的第一次出现在p。

的注释1
  

David B. Searls,用明确的条款语法研究DNA的语言学。 NACLP 1989,第1卷。

答案 3 :(得分:-1)

您也可以尝试以下方法:

member(X,L) :- append(_,[X|_],L).