【问题标题】:Prolog filter a list of all elements for which a custom goal failsProlog 过滤自定义目标失败的所有元素的列表
【发布时间】:2016-07-31 15:54:32
【问题描述】:

我正在尝试编写一个谓词filter(List, PredName, Result),它过滤掉目标PredName 失败的所有元素的List,然后返回Result 列表。谓词PredName/1 应在调用过程filter/3 时定义,例如:

test(N) :- N >= 0

然后可以进行如下查询:

?- filter([-6,7,-1,0], test, L)
L = [7, 0];
no

【问题讨论】:

    标签: prolog meta-predicate


    【解决方案1】:

    如果您使用的是 SWI-Prolog,则可以使用来自 "apply" libraryexclude 谓词

    【讨论】:

      【解决方案2】:

      我确定存在一个内置操作来执行此操作...但本质上您只是尝试对传递谓词的列表成员执行 findall。试试这个过滤器的实现。运行 findall 的第二个 arg 直到所有结果都用完并且 M 的所有值都收集到 Result 中。

      filter(List,PredName,Result) :-
        findall(M, ( member(M, List), call(PredName,M)), Result).
      

      【讨论】:

        【解决方案3】:

        一种方法是使用递归和“调用”谓词

        filter([],_,[]).
        filter([H|T], PredName, [H|S]) :-  call(PredName,H),filter(T,PredName,S),!.
        filter([H|T], PredName, S) :- filter(T,PredName,S).
        

        另一种方法是使用=.. (univ) 运算符代替调用。

        filter([],_,[]).
        filter2([H|T], PredName, [H|S]) :-  Goal =.. [PredName,H],Goal,filter(T,PredName,S),!.
        filter([H|T], PredName, S) :- filter(T,PredName,S).
        

        =.. 运算符采用包含谓词名称及其参数的列表并返回新创建的术语。例如:

        ?-X =.. [f,a,b].
        X = f(a, b).
        

        【讨论】:

        • 请注意,像您一样使用(=..)/2 会将PredName 限制为一个原子。这意味着 Goal 必须是 arity 1 的谓词。使用 call/2 会更加灵活:现在您可以使用任何合适的谓词,arity >= 1。这通常非常有用。另请参阅@Nick Main 的回答。
        • @false 你能举个例子来澄清你说的话吗?
        • 一个最小的例子:考虑你想过滤掉所有元素E,这样E \== 3。使用(=..)/2,您必须定义一个新谓词noteqeq3(E) :- E \== 3.,但使用call/2,您可以直接交出\==(3)
        猜你喜欢
        • 2021-12-13
        • 2018-11-05
        • 1970-01-01
        • 2015-10-13
        • 2019-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多