如何使用匿名变量检查列表中的某些元素

时间:2017-10-08 15:22:52

标签: prolog

想象一下像L = [1, 4, _, 5, _]这样的列表 如果我想检查4是否是此列表的成员,我可以执行以下操作:member(4, L)。这将返回True,因为此列表中有4。但是,对于我检查的每个元素,它使用member / 2返回true。当然,这是因为匿名变量可以与任何东西匹配。所以它总会返回True。我想知道是否有一种方法可以从列表L中删除所有匿名变量。因此NewList[1, 4, 5]

3 个答案:

答案 0 :(得分:1)

为了检查某些项目是否在包含匿名变量的列表中,您首先需要(暂时)从该列表中删除所有匿名变量。为此,您可以使用内置谓词subtract/3var/1

subtract/3:第一个元素是您要检查的列表,第二个元素是包含要从列表中删除的元素的列表,第三个元素是结果列​​表。

var/1:只包含一个元素(X),如果X是未绑定的变量,则返回True

在这种情况下,我们希望subtractTrue时返回var(X)的每个元素(X)var(_)。在代码中,这写为subtract/3

现在我们只需填写subtract(L, [var(_)], NewList).这样的谓词:NewList

member/2现在只存储绑定变量,而change现在可以按预期工作。

答案 1 :(得分:1)

除了从列表中删除变量然后使用member/2之外,您还可以选择实现自己的谓词来描述member/2 - 类似于非变量元素的关系:

nonvarmember(X,[Y|_]) :-
   nonvar(Y),                % only try to unify with X if Y is not a variable
   X=Y.
nonvarmember(X,[_Y|Ys]) :-
   nonvarmember(X,Ys).

现在让我们看看这个谓词的工作原理:

?- nonvarmember(4,[1,4,_,5,_]).
true ;
false.

?- nonvarmember(4,[1,_,_,5,_]).
false.

?- nonvarmember(4,[1,4,_,5,_,Z]).
true ;
false.

但是,第一个参数仍然可以是变量:

?- nonvarmember(X,[1,4,_,5,_,Z]).
X = 1 ;
X = 4 ;
X = 5 ;
false.

?- nonvarmember(X,[_,_,_]).
false.

但请注意,如果首先从列表中删除变量元素并随后使用member/2或使用nonvarmember/2,则会遇到以下问题:List-elements在您检查成员资格未被计算后实例化,因此可能导致不健全的答案。以下示例说明了问题:

?- A=4, nonvarmember(4,[A,B,C]).
A = 4 ;
false.

?- nonvarmember(4,[A,B,C]), A=4.
false.

答案 2 :(得分:1)

如果是Swi-Prolog(至少),您可以使用include / 3和exclude / 3谓词来过滤列表。您可以将这些谓词与var / 1和nonvar / 1一起使用,以从列表中删除变量。

在您的特定情况下,检查4是否属于列表[1,4,_,5,_]可以按如下方式进行:

Y-1 Kandydaci = CALCULATE(
    distinctcount(getDataForTeb[ID_DANE_OSOBOWE]);
    DATESBETWEEN(
        getDataForTeb[Złożenie podania];
        DATE(YEAR(now())-1;4;1);
        IF(DATE(YEAR(NOW())-1;MONTH(NOW());DAY(NOW()))<=DATE(YEAR(NOW())-1;11;30);
            DATE(YEAR(NOW())-1;MONTH(NOW());DAY(NOW()));DATE(YEAR(NOW())-1;11;30)));
            ISBLANK(getDataForTeb[REZYGNACJA_DATA]))

Y-1 Kandydaci cumulative = CALCULATE(
    DISTINCTCOUNT(getDataForTeb[ID_DANE_OSOBOWE]);
    FILTER(
        ALL (getDataForTeb);
        AND (
            getDataForTeb[Złożenie podania] <= MAX(getDataForTeb[Złożenie podania])-364;
            AND (
                getDataForTeb[Złożenie podania] <= DATE(YEAR(NOW())-1; 11; 30);
                getDataForTeb[Złożenie podania] >= DATE(YEAR(NOW())-1; 4; 1)
            )
        )
    );
    ISBLANK(getDataForTeb[REZYGNACJA_DATA])
)