Sticky Notes: A mini-DSL for taking notes with symbolic objects.¶
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