Declarative Loops and List Comprehensions (not in ISO)

Prolog relies on recursion to describe loops. This has basically remained the same since Prolog's inception 35 years ago. Many other languages provide powerful loop constructs. For example, the foreach statement in C# and the enhanced for statement in Java are very powerful for iterating over collections. Functional languages provide higher-order functions and list comprehensions for creating collections, and for iterating over collections. The lack of powerful loop constructs has arguably made Prolog less acceptable to beginners, and less productive to experienced programmers, because it is often tedious to define small auxiliary recursive predicates for loops. The emergence of constraint programming constructs, such as CLP(FD), has further revealed this weakness of Prolog as a host language.

B-Prolog provides a built-in, called foreach, and the list comprehension notation for writing repetition. The foreach built-in has a very simple syntax and semantics. For example, foreach(A in [a,b], I in 1..2, write((A,I))) outputs four tuples: (a,1), (a,2), (b,1), and (b,2). Syntactically, foreach is a variable-length call whose last argument specifies a goal that should be executed for each combination of values in a sequence of collections. A foreach call may also give a list of variables that are local to each iteration, and a list of accumulators that can be used to accumulate values from each iteration. With accumulators, users can use foreach in order to describe recurrences for computing aggregates. Recurrences have to be read procedurally, and thus do not fit well with Prolog. For this reason, B-Prolog borrows list comprehensions from functional languages. A list comprehension is a list whose first element has the functor ':'/2. A list of this form is interpreted as a list comprehension in calls to '@='/2, and in some other contexts. For example, the query X@=[(A,I) : A in [a,b], I in 1..2] binds X to the list [(a,1),(a,2),(b,1),(b,2)]. A list comprehension is treated as a foreach call with an accumulator in the implementation.

Neng-Fa Zhou 2013-01-25