如何使用PL-Unit以任何顺序测试非确定性谓词?

时间:2016-12-16 18:30:50

标签: unit-testing prolog

  • 我想用PL-Unit 在Prolog中对非确定性谓词进行单元测试。

  • 我想“断言”我在测试中指定的解决方案是 谓词的唯一 解决方案。

  • 不关心订单,在测试中指定了每个解决方案。

SWI-Prolog手册说:

SWI-Prolog手册有一个很棒的部分叫testing non-deterministic predicates ...

  

2.2.3测试非确定性谓词

     

非确定性谓词成功为零次或多次。他们的结果使用findall / 3或setof / 3进行测试,然后进行值检查或使用all或set选项。以下是等效测试:

test(member) :-
        findall(X, member(X, [a,b,c]), Xs),
        Xs == [a,b,c].

test(member, all(X == [a,b,c])) :-
        member(X, [a,b,c]).

这几乎是完全我需要的东西。但是,要传递这些测试,必须以正确的顺序指定输出:[a, b, c]。我希望能够在任何顺序中指定它并仍然有测试通过。

我正在尝试的一个例子:

假设我正在测试这个(假设的)谓词,它有两个解决方案。

specialNumber(X) :-
    X is 2;
    X is 4.

我可以像这样编写一个通过单元测试......

% PASSES!
test(specialNumber, all(X == [2, 4])) :-
        specialNumber(X).

但如果我交换了解决方案的顺序,它就会失败......

% FAILS!
test(specialNumber, all(X == [4, 2])) :-
        specialNumber(X).

无论找到解决方案的顺序如何,我如何进行此测试?

1 个答案:

答案 0 :(得分:1)

考虑使用 setof/3 代替findall/3来收集排序

例如,考虑到谓词的略微重写定义:

special_number(X) :-
        (   X #= 2
        ;   X #= 4
        ).

我们可以定义以下PlUnit测试:

:- begin_tests(all).

test(solutions, Solutions = [2,4]) :-
        setof(X, special_number(X), Solutions).

:- end_tests(all).

如果您重写您的谓词,继续

special_number(X) :-
        (   X #= 4
        ;   X #= 2
        ).

在这种情况下,我们有:

?- findall(X, special_number(X), Ls).
Ls = [4, 2].

?- setof(X, special_number(X), Ls).
Ls = [2, 4].

作为setof/3的替代方案,您可以使用:

  • findall/3
  • 然后使用sort/2手动对解决方案进行排序。

您可以阅读相关主题:

  • 条款的标准顺序
  • bagof/3
  • (@<)/2

我将添加必要的和指令作为练习运行上面的示例。