我不明白为什么下划线扎根于元谓词

问题描述 投票:0回答:1

我正在使用 SWI-PROLOG。

给定一个列表,其中几乎所有元素都是复合术语,例如:

 ?- MyList = [json([a=1, b=2]), json([a=4, b=1]), 999, json([a=7, b=2])]. 

我只想过滤复合术语元素,所以我尝试了以下操作:

?- MyList= ..., include(=(json(_)), MyList, FilteredElems). 
FilteredElems = [json([a=1, b=2])]. 

我希望得到以下结果

FilteredElems= [json([a=1, b=2]), json([a=4, b=1]), json([a=7, b=2])]
但只包括第一个结果。

我发现在第一次调用谓词后,下划线会接地为:

[a=1, b=2]
值,因此下一次尝试使用
json(_)
成功统一会失败。

是否存在解决此问题的干净方法?我错过了什么吗?

为了测试下划线的基础,我使用了修改后的包含版本:

inc(Goal, List, Included) :-
    inc_(List, Goal, Included).

inc_([], _, []).
inc_([X1|Xs1], P, Included) :-
      (   
          writef("Calling call(%t, %t)\n", [P, X1]),
          call(P, X1)
      ->  Included = [X1|Included1], 
          writef("\tTrue\n")
      ;   Included = Included1,
          writef("\tFalse\n")
      ),
      inc_(Xs1, P, Included1).

prolog swi-prolog
1个回答
0
投票

您所看到的行为是由统一期间实例化(接地)的 Prolog 变量引起的。当您使用

json(_)
时,下划线变量
_
会实例化为第一个匹配短语
[a=1, b=2]
,并且由于下划线变量不再是自由变量,因此与其他术语统一的进一步努力会失败。您可以采用不同的方法来解决此问题。编写一个谓词来迭代测试列表中的每个成员并将其包含在结果列表中(如果它是复合术语)是一种仅从列表中过滤复合术语项目的技术。这是谓词的示例:

filter_compound_terms([], []).
filter_compound_terms([H|T], Filtered) :-
    (   compound(H)
    ->  Filtered = [H|Rest]
    ;   Filtered = Rest
    ),
    filter_compound_terms(T, Rest).

此谓词可用于过滤您的列表,如下所示:

?- MyList = [json([a=1, b=2]), json([a=4, b=1]), 999, json([a=7, b=2])],
   filter_compound_terms(MyList, FilteredElems).

FilteredElems = [json([a=1, b=2]), json([a=4, b=1]), json([a=7, b=2])].

该谓词递归地传递列表中的每个成员,包括结果列表中的复合术语。

© www.soinside.com 2019 - 2024. All rights reserved.