Meta-Predicates & Higher-Order¶
Clausal provides meta-predicates for collecting solutions and higher-order list predicates for functional-style list processing. Meta-predicates are compiler special forms (compiled inline); higher-order list predicates are builtins that take goal closures.
Meta-Predicates (Compiler Special Forms)¶
These are compiled inline by the compiler — they are not dispatched as builtins.
FindAll/3¶
FindAll(Template, Goal, Bag) — collect all instances of Template for which Goal succeeds.
If Goal has no solutions, Bag is unified with [].
BagOf/3¶
BagOf(Template, Goal, Bag) — like FindAll, but fails if Goal has no solutions. Also respects ^ (existential quantification) for free variables.
SetOf/3¶
SetOf(Template, Goal, Set) — like BagOf, but returns a sorted list with duplicates removed.
ForAll/2¶
ForAll(Condition, Action) — succeeds if for every solution of Condition, Action also succeeds.
Call/N¶
Call/1..8 invokes a goal closure with 0–7 extra arguments. CallGoal/1..8 are aliases.
These are primarily used with lambdas:
Higher-Order List Predicates¶
These builtins take a goal as their first argument — either a lambda (goal closure) or a predicate reference (builtin or user-defined). All use committed choice — they take the first solution from the goal for each element.
MapList/2¶
MapList(Goal, List) — succeeds if Goal succeeds for every element of List.
# With a lambda
all_positive(XS) <- MapList((X <- (X > 0)), XS)
# With a builtin predicate
all_numbers(XS) <- MapList(IsNumber, XS)
MapList/3¶
MapList(Goal, List, ResultList) — apply a binary goal to each element, collecting results.
Filter/3¶
Filter(Goal, List, Filtered) — keep elements for which Goal succeeds.
# With a lambda
positives(XS, PS) <- Filter((X <- (X > 0)), XS, PS)
# With a builtin predicate
keep_numbers(XS, NS) <- Filter(IsNumber, XS, NS)
Exclude/3¶
Exclude(Goal, List, Remaining) — keep elements for which Goal fails (complement of Filter).
FoldLeft/4¶
FoldLeft(Goal, List, Acc0, Result) — left fold with a ternary goal closure.
fold_sum(XS, S) <- FoldLeft(((ELEM, ACC, R) <- (R := ACC + ELEM)), XS, 0, S)
fold_product(XS, P) <- FoldLeft(((ELEM, ACC, R) <- (R := ACC * ELEM)), XS, 1, P)
TakeWhile/3¶
TakeWhile(Goal, List, Prefix) — longest prefix where Goal succeeds for each consecutive element.
DropWhile/3¶
DropWhile(Goal, List, Suffix) — suffix after dropping the longest prefix where Goal succeeds.
Span/4¶
Span(Goal, List, Yes, No) — TakeWhile + DropWhile in one pass.
GroupBy/3¶
GroupBy(Goal, List, Groups) — group consecutive elements by key projected via Goal(Elem, Key).
SortBy/3¶
SortBy(Goal, List, Sorted) — sort by key projected via Goal(Elem, Key). Stable sort.
MaxBy/3, MinBy/3¶
MaxBy(Goal, List, Max) / MinBy(Goal, List, Min) — element with largest/smallest key. Fails on empty list.
FilterMap/3¶
FilterMap(Goal, List, Result) — map + filter in one pass. Calls Goal(Elem, Out) for each element; keeps Out when goal succeeds, skips when it fails.
Additional List Predicates¶
| Builtin | Arity | Description |
|---|---|---|
Unzip |
3 | Unzip(Pairs, Keys, Values) — split list of pairs |
PairKeys |
2 | PairKeys(Pairs, Keys) — extract keys from pairs |
PairValues |
2 | PairValues(Pairs, Values) — extract values from pairs |
Combining Meta-Predicates with Lambdas
Meta-predicates take inline goal expressions (not closures), so lambdas aren't needed:
```clausal
skip¶
# FindAll with inline goal — no lambda required
squares(NS, SQS) <- FindAll(SQ, (In(X, NS), SQ := X * X), SQS)
# ForAll with inline condition and action
all_positive(NS) <- ForAll(In(X, NS), X > 0)
```
Higher-order list predicates take either lambdas or predicate references:
```clausal
skip¶
# Filter with lambda
positives(XS, PS) <- Filter((X <- (X > 0)), XS, PS)
# Filter with a builtin predicate directly
keep_ints(XS, IS) <- Filter(IsInt, XS, IS)
```
See [Lambdas](lambdas.md) for full lambda syntax and semantics.
Test coverage
tests/test_meta.py(23 tests): FindAll, BagOf, SetOf, ForAll, Call/N,.clausalintegrationtests/test_higher_order.py(34 tests): MapList/2,3, Filter/3, Exclude/3, FoldLeft/4, builtin predicates as argumentstests/fixtures/builtin_as_arg.clausal(5 tests): Filter/MapList with builtin predicates (IsNumber, IsInt, Succ)