Skip to content

Commit 6aff1e6

Browse files
committed
logic: add gensym() for fresh unique symbols (#230)
Per Norvig's suggestion on #230, add a Lisp-style gensym(): successive calls return distinct logic symbols s_0, s_1, s_2, ... (Expr objects), which makes it easy to build an array/dict of symbols or to standardize apart, without having to invent names by hand. Test added.
1 parent 517a05a commit 6aff1e6

2 files changed

Lines changed: 22 additions & 0 deletions

File tree

‎aima/logic.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,20 @@ def is_prop_symbol(s):
159159
return is_symbol(s) and s[0].isupper()
160160

161161

162+
def gensym(prefix='s_'):
163+
"""Return a fresh logic symbol with a unique name, like Lisp's ``gensym`` [#230].
164+
165+
Successive calls return distinct symbols ``s_0``, ``s_1``, ``s_2``, ... -- handy
166+
for building an array or dict of symbols, or for standardizing apart. Pass a
167+
``prefix`` to control the name stem.
168+
"""
169+
gensym.counter += 1
170+
return Expr(prefix + str(gensym.counter))
171+
172+
173+
gensym.counter = -1
174+
175+
162176
def variables(s):
163177
"""Return a set of the variables in expression s.
164178
>>> variables(expr('F(x, x) & G(x, y) & H(y, z) & R(A, z, 2)')) == {x, y, z}

‎tests/test_logic.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,5 +441,13 @@ def test_hybrid_wumpus_agent_first_action():
441441
assert agent.current_position.get_location() == (1, 1)
442442

443443

444+
def test_gensym():
445+
s1, s2, s3 = gensym(), gensym(), gensym()
446+
assert len({s1, s2, s3}) == 3 # all distinct
447+
assert all(is_symbol(s.op) for s in (s1, s2, s3)) # genuine symbols
448+
assert gensym('v_').op.startswith('v_') # custom prefix
449+
assert variables(s1 | s2) == {s1, s2} # usable in expressions
450+
451+
444452
if __name__ == '__main__':
445453
pytest.main()

0 commit comments

Comments
 (0)