loop package:rel8

loop allows the construction of recursive queries, using Postgres' WITH RECURSIVE under the hood. The first argument to loop is what the Postgres documentation refers to as the "non-recursive term" and the second argument is the "recursive term", which is defined in terms of the result of the "non-recursive term". loop uses UNION ALL to combine the recursive and non-recursive terms. Denotionally, loop s f is the smallest set of rows r such that
r == s `unionAll` (r >>= f)
Operationally, loop s f takes each row in an initial set s and supplies it to f, resulting in a new generation of rows which are added to the result set. Each row from this new generation is then fed back to f, and this process is repeated until a generation comes along for which f returns an empty set for each row therein.
loopDistinct is like loop but uses UNION instead of UNION ALL to combine the recursive and non-recursive terms. Denotationally, loopDistinct s f is the smallest set of rows r such that
r == s `union` (r >>= f)
Operationally, loopDistinct s f takes each distinct row in an initial set s and supplies it to f, resulting in a new generation of rows. Any rows returned by f that already exist in the result set are not considered part of this new generation by loopDistinct (in contrast to loop). This new generation is then added to the result set, and each row therein is then fed back to f, and this process is repeated until a generation comes along for which f returns no rows that don't already exist in the result set.