9  Set Predicates

The goal

(%bag-of X G Bag)

unifies with Bag the list of all instantiations of X for which G succeeds. Thus, the following query asks for all the things known — ie, the collection of things such that someone knows them:

(%which (things-known)
  (%let (someone x)
    (%bag-of x (%knows someone x)
      things-known)))
=>([things-known
      (TeX Scheme Prolog
       Penelope TeX Prolog
       Odysseus TeX calculus)])

This is the only solution for this goal:

(%more) =>#f

Note that some things — eg, TeX — are enumerated more than once. This is because more than one person knows TeX. To remove duplicates, use the predicate %set‑of instead of %bag‑of:

(%which (things-known)
  (%let (someone x)
    (%set-of x (%knows someone x)
      things-known)))
=>([things-known
      (TeX Scheme Prolog
       Penelope Odysseus calculus)])

In the above, the free variable someone in the %knows-goal is used as if it were existentially quantified. In contrast, Prolog’s versions of %bag‑of and %set‑of fix it for each solution of the set-predicate goal. We can do it too with some additional syntax that identifies the free variable. Eg,

(%which (someone things-known)
  (%let (x)
    (%bag-of x
      (%free-vars (someone)
        (%knows someone x))
      things-known)))
=>([someone Odysseus]
    [things-known
      (TeX Scheme Prolog
       Penelope)])

The bag of things known by one someone is returned. That someone is Odysseus. The query can be retried for more solutions, each listing the things known by a different someone:

(%more) =>([someone Penelope]
            [things-known
              (TeX Prolog
	       Odysseus)])
(%more) =>([someone Telemachus]
            [things-known
              (TeX calculus)])
(%more) =>#f

Schelog also provides two variants of these set predicates, viz., %bag‑of‑1 and %set‑of‑1. These act like %bag‑of and %set‑of but fail if the resulting bag or set is empty.