Dear schemers,
For your information, we have been using "our own" version of conjoin
and disjoin for the past decade. Only to find that srfi-235 has made
them available with a different meaning.
For conjoin srfi-235 states:
The predicates are applied in turn to the args as follows: If a call to
a predicate returns false, no more predicates are applied and #f is
returned. If all predicates return true, then the last value is
returned. If there are no predicates, #t is returned.
But this language is ambiguous.
I found two LISP interpretations that are consistent with each other and
our interpretation, but disagree with the current version of conjoin in
srfi-235, see:
https://www.lisppad.app/libraries/lispkit/lispkit-combinator,
conjoin: Returns a function invoking all functions f ... and combining
the results with and. ((conjoin f1 f2 ...) x ...) is equivalent to (and
(f1 x ...) (f2 x ...) ...).
and https://common-lisp-libraries.readthedocs.io/alexandria/
(defun conjoin (predicate &rest more-predicates)
"Returns a function that applies each of PREDICATE and MORE-PREDICATE
functions in turn to its arguments, returning NIL if any of the predicates
returns false, without calling the remaining predicates. If none of the
predicates returns false, returns the primary value of the last predicate."
(if (null more-predicates)
predicate
(lambda (&rest arguments)
(and (apply predicate arguments)
;; Cannot simply use CL:EVERY because we want to return the
;; non-NIL value of the last predicate if all succeed.
(do ((tail (cdr more-predicates) (cdr tail))
(head (car more-predicates) (car tail)))
((not tail)
(apply head arguments))
(unless (apply head arguments)
(return nil)))))))
I propose to change the current meaning and the implementation of both
conjoin and disjoin in srfi-235 to the ones here below:
(define (conjoin . procs)
"Like AND with procedures, i.e. ((conjoin p1 p2 ...) x ...) is equivalent
to (and (p1 x ...) (p2 x ...) ...)."
(lambda args
(every (lambda (proc) (apply proc args)) procs)))
(define (disjoin . procs)
"Like OR with procedures, i.e. ((disjoin p1 p2 ...) x ...) is equivalent
to (or (p1 x ...) (p2 x ...) ...)."
(lambda args
(any (lambda (proc) (apply proc args)) procs)))
Where I have replaced predicates with procedures, apply each procedure
to all of the arguments, and use every and any instead of a dedicated
loop algorithm.
Please also see guile issue 115:
https://codeberg.org/guile/guile/pulls/115 and the updated tests.
Kind regards,
Regtur.
--
Rutger van Beusekom <xxxxxx@reasonable-sourcery.coop>
Free Software for Correctness
Correctness for Free Software
https://reasonable-sourcery.coop