[net.lang.prolog] Arbitrary arity for predicates

Ken%MIT-OZ@sri-unix.UUCP (06/12/84)

I have been arguing for a long time that Prolog predicates
should have arbitrary arity.  Many predicates such as sum,
product, =, append, and, or, ... should take any number
of arguments.  The advantages of this are well-known to
Lisp hackers.  I often present the following definition
of append and point out that it is both more convenient
to append 3 lists by saying (append ?all ?a ?b ?c) but
that the programming need not be bother by the fact that
append is logically associative but not computationally.
(E.g. (and (append ?ab ?a ?b) (append ?all ?ab ?c))
costs more than the equivalent (and (append ?bc ?b ?c)
(append ?all ?a ?bc)).)  (One disadvantage of arbitrary
arity is that one needs to change Prolog convention
about putting the ``output'' last when representing a
function as a predicate and put it first instead.)

(define-predicate append
  :(options
    (argument-list (appended &rest parts))
    (documentation
     "succeeds if APPENDED unifies with the result of appending
                                                        PARTS."))
  ((append ()))
  ((append ?x ?x))
  ((append ?y () ?y))
  ((append (?first . ?rest-x-and-y) (?first . ?rest-x) ?y)
   (append ?rest-x-and-y ?rest-x ?y))
  ((append (?first . ?rest-x-and-y) (?first . ?rest-x) . ?y)
   (append ?rest-x-and-y ?rest-x . ?y)))

For those worried about the semantics of arbitrary arity it
can be seen as syntatic and compiler support for predicates
with just one argument which is an s-expression.

I have long been bothered by the fact that some queries
to append go into loops needlessly.  For example,

(append (a) ?x ?y (b)) will loop rather than fail.

(So of course does Prolog given,

append(X,Z,[a]),append(Z,Y,[b]).)

Mats Carlsson came up with a more consise way of writing
append that doesn't have these difficulties.

(define-predicate append
  :(options
    (argument-list (appended &rest parts))
    (documentation
     "succeeds if APPENDED unifies with the result of appending
                                                        PARTS."))
  ((append ()))
  ((append ?x () . ?y)
   (append ?x . ?y))
  ((append (?first . ?rest-x-and-y) (?first . ?rest-x) . ?y)
   (append ?rest-x-and-y ?rest-x . ?y)))

I think his version will always do better than the one
which has a conjunction of calls to append.

Comments?

-- Ken Kahn