[m-users.] A predicate taking a lists of predicates as input?

Zoltan Somogyi zoltan.somogyi at runbox.com
Fri Sep 26 15:28:39 AEST 2025



On Wed, 24 Sep 2025 17:35:50 +0200, Anders Lundstedt <mercury-users at anderslundstedt.se> wrote:
> Sorry, tried to simplify too much. Here is a correct example:
> 
> :- pred r_a(list(char)::in, list(char)::out) is semidet.
> :- pred r_b(list(char)::in, list(char)::out) is semidet.
> r_a --> ['a'].
> r_b --> ['b'].
> % gives compilation error, but not if the both the determinism of ? and of
> % this predicate is changed to semidet, in which case we get warnings about
> % too loose determinism for ?
> :- pred test_1(list(char)::in, list(char)::out) is det.
> test_1 --> ?([r_a, ?([r_b])]).

The issue here is that your ? predicate (which I will call "optional") is det,
but seems to take a list of semidet predicates (closures), which causes
a determinism mismatch if you want to include a closure of optional
itself in one of those lists.

The simple solution here is to put a wrapper around this closure to do
what is effectively a determinism cast. This can be done using code
like this:

:- pred optional_semidet(...) is semidet.

optional_semidet(In, Out) :-
    ( if semidet_succeed then
        optional(In, Out)
    else
        fail
    ).

Operationally, this does exactly the same as optional(In, Out), but
the compiler handles it as a semidet predicate that just happens
to always succeed.

Then, whenever you want to put a closure of optional in a position
where you need a det predicate, you pass a closure of optional_semidet
instead.

I would also point you to the link named "The XY problem" on the
https://mercurylang.org/contact.html page. It seems applicable
in this instance.

Zoltan.


More information about the users mailing list