License: Public Domain , Load it with Quicklisp: (ql:quickload "bubble-operator-upwards")
Library type: Utility function , Project complexity: Trivial

bubble-operator-upwards is a function that "bubbles an operator upwards" in a form,
demultiplexing all alternative branches by way of cartesian product.

This operation is notably useful for easy implementation of certain kinds of shorthand notations in macros.
A cartesian-product function is also exported, as it's needed to implement the main function.


Here are a few examples:

(bubble-operator-upwards 'and '(plate (and ham eggs) beans))
(bubble-operator-upwards 'alt '(section (alt 1 2 3) - (alt "a" "b"))
                         :result-kind :branches)
((SECTION 1 - "a") (SECTION 1 - "b")
 (SECTION 2 - "a") (SECTION 2 - "b")
 (SECTION 3 - "a") (SECTION 3 - "b"))
(bubble-operator-upwards 'or '(>> (or ul ol)
                                  (or (:class (or "important" "urgent"))
                                      (id "first-priority"))))
(OR (>> UL (:CLASS "important"))
    (>> UL (:CLASS "urgent"))
    (>> UL (ID "first-priority"))
    (>> OL (:CLASS "important"))
    (>> OL (:CLASS "urgent"))
    (>> OL (ID "first-priority")))


Dictionary » bubble-operator-upwards

Package bubble-operator-upwards


This package is also nicknamed bubble-op-up.

Simply (:import-from #:bubble-operator-upwards #:bubble-operator-upwards) from your defpackage. Don't (:use)!

Function bubble-operator-upwards

operator form &key (result-kind :abridged) (if-collapsed nil) (collapsed-identity [...]) => result

Arguments and Values

  • operator -- A symbol.
  • form -- A form.
  • result-kind -- One of the keywords :branches, :full or :abridged.
  • if-collapsed -- :error or nil.
  • collapsed-identity -- An object. The default is:
    (ecase result-kind
      ((:full :abridged)
       (list operator))
      (:branches nil))


Bubbles operator upwards in form, demultiplexing all alternative branches by way of cartesian product.
Hard to describe formally, but the examples above should give some inspiration for the basic effect,
and some experimentation in the REPL is recommended.

result-kind is one of :branches, :full or :abridged:

  • :branches simply returns the demultiplexed branches.
  • :full returns the same result as :branches would, except wrapped in a cons whose CAR is operator.
  • :abridged returns the same result as :full would, except if there's only one branch, only that branch is returned, without the wrapping.

if-collapsed and collapsed-identity determine what to do if the number of branches "collapses" to zero.
if-collapsed is :error or nil. If it's nil and the result is indeed collapsed, then the value of collapsed-identity will be returned.

Dictionary » cartesian-product

Function bubble-op-up:cartesian-product

&rest possibility-groups => cartesian-product

Arguments and Values

  • possibility-groups -- A list.


Returns the cartesian-product of all possible combinations from possibility-groups, as a list.
This function is inherently needed to implement bubble-operator-upwards, so might as well export it...

(bubble-op-up:cartesian-product '(1 2) '(a b c))
((1 A) (1 B) (1 C)
 (2 A) (2 B) (2 C))