Find number of successes from a list of terms/goals

93 views Asked by At

I have written the following predicate exactly/2 that succeeds if exactly N of the numbers in the list L are equal to 1:

:- pred exactly(int, list(int)).
:- mode exactly(in, in) is semidet.
:- mode exactly(out, in) is det.
exactly(N, L) :-
    length(filter(pred(X::in) is semidet :- (X = 1), L), N).

For example, the call exactly(X, [1, 0, 0, 1, 0, 1]) will bind X to 3.

I want to create something similar, but for predicates: I want to write a predicate that succeeds if exactly N goals from the list L are successful.

For example, the call exactly(X, [true, false, member(1, [1, 2, 3]), member(0, [1, 2, 3])]) should bind X to 2.

1

There are 1 answers

0
Zoltan Somogyi On

Actually, this can be done, as shown by this code:

:- module exactly.

:- interface.
:- import_module io.

:- pred main(io::di, io::uo) is det.

:- implementation.

:- import_module int.
:- import_module list.

main(!IO) :-
    Test1 = list_member(1, [1, 2, 3]),
    Test2 = list_member(0, [1, 2, 3]),
    Tests = [Test1, Test2],
    exactly(N, Tests),
    io.write_line(N, !IO).

:- pred exactly(int::out, list((pred))::in(list_skel((pred) is semidet)))
    is det.

exactly(0, []).
exactly(N, [Test | Tests]) :-
    exactly(NTail, Tests),
    ( if Test then
        N = NTail + 1
    else
        N = NTail
    ).

:- pred list_member(T::in, list(T)::in) is semidet.

list_member(E, L) :-
    list.member(E, L).

The predicate list_member tells the compiler which mode of list.member you want to call. As for true and false, you would need to define predicates of those names as well. (By default, they exist as goals only.)