Sticky Notes: A mini-DSL for taking notes with symbolic objects.

Open in Colab

This notebook demostrates how to create domain-specific languages (DSL) in Python with symbolic placeholding and manipulation.

!pip install pyglove
import pyglove as pg

Developing DSL primitives

In this example, we introduce a StickyNote class, which can be passed to an arbitrary field within a symbolic object. By subclassing pg.PureSymbolic, StickNote objects are treated as pure symbolic values, thus delaying the construction of their owning objects.

@pg.members([
  ('value', pg.typing.Any()),
  ('notes', pg.typing.Str())
])
class StickyNote(pg.PureSymbolic, pg.Object):
  """StickyNote is a pure symbolic object that can be used as placeholders."""

# Transform to replace a node in the tree with a StickyNote object.
def note(value, path, text):
  return pg.patching.patch_on_path(
      value, path, value_fn=lambda x: StickyNote(x, text))

# Transform to replace StickyNote object with original value.
def denote(value):
  """Remove notes from an symbolic object."""
  return pg.patching.patch_on_type(
      value, StickyNote, value_fn=lambda x: x.value)

Use DSL primitives with any symbolic objects

@pg.symbolize
def foo(x, y):
  x = x() if callable(x) else x
  y = y() if callable(y) else y
  return x + y

# Create a symbolic object.
f = foo(foo(1, 2), foo(3, 4))

# Take notes on sub-nodes 'x' and 'y'.
note(f, 'x', 'this value is copied somewhere.')
note(f, 'y.x', 'this value is not copied.')
print(f)
foo(
  x = StickyNote(
    value = foo(
      x = 1,
      y = 2
    ),
    notes = 'this value is copied somewhere.'
  ),
  y = foo(
    x = StickyNote(
      value = 3,
      notes = 'this value is not copied.'
    ),
    y = 4
  )
)
# Query noted nodes.
pg.query(f, where=lambda v: isinstance(v, StickyNote))
{'x': StickyNote(value=foo(x=1, y=2), notes='this value is copied somewhere.'),
 'y.x': StickyNote(value=3, notes='this value is not copied.')}
# Remove notes so `f` can be evaluated.
print(denote(f)())
10