Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions etuples/dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,39 @@
from .core import etuple, ExpressionTuple

try:
from unification.core import _reify, _unify
from unification.core import _reify, _unify, isvar
except ModuleNotFoundError:
pass
else:

def _unify_ExpressionTuple(u, v, s):
return _unify(u._tuple, v._tuple, s)
return _unify(getattr(u, "_tuple", u), getattr(v, "_tuple", v), s)

_unify.add((ExpressionTuple, ExpressionTuple, Mapping), _unify_ExpressionTuple)
_unify.add((tuple, ExpressionTuple, Mapping), _unify_ExpressionTuple)
_unify.add((ExpressionTuple, tuple, Mapping), _unify_ExpressionTuple)

def _reify_ExpressionTuple(u, s):
return etuple(*_reify(u._tuple, s))
# The point of all this: we don't want to lose the expression
# tracking/caching information.
res = _reify(u._tuple, s)

res_same = tuple(
a == b for a, b in zip(u, res) if not isvar(a) and not isvar(b)
)

if len(res_same) == len(u) and all(res_same):
# Everything is equal and there are no logic variables
return u

if getattr(u, "_parent", None) and all(res_same):
# If we simply swapped-out logic variables, then we don't want to
# lose the parent etuple information.
res = etuple(*res)
res._parent = u._parent
return res

return etuple(*res)

_reify.add((ExpressionTuple, Mapping), _reify_ExpressionTuple)

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-e ./
unification
logical-unification
ipython
coveralls
pydocstyle>=3.0.0
Expand Down
43 changes: 42 additions & 1 deletion tests/test_dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,45 @@ def test_unification():
res = unify(etuple(add, 1, 2), cons(a_lv, b_lv), {})
assert res == {a_lv: add, b_lv: etuple(1, 2)}

assert reify(cons(a_lv, b_lv), res) == etuple(add, 1, 2)
res = reify(cons(a_lv, b_lv), res)
assert isinstance(res, ExpressionTuple)
assert res == etuple(add, 1, 2)

et = etuple(a_lv,)
res = reify(et, {a_lv: 1})
assert isinstance(res, ExpressionTuple)

et = etuple(a_lv,)
# We choose to allow unification with regular tuples.
if etuple(1) == (1,):
res = unify(et, (1,))
assert res == {a_lv: 1}

et = etuple(add, 1, 2)
assert et.eval_obj == 3

res = unify(et, cons(a_lv, b_lv))
assert res == {a_lv: add, b_lv: et[1:]}

# Make sure we've preserved the original object after deconstruction via
# `unify`
assert res[b_lv]._parent is et
assert ((res[a_lv],) + res[b_lv])._eval_obj == 3

# Make sure we've preserved the original object after reconstruction via
# `reify`
rf_res = reify(cons(a_lv, b_lv), res)
assert rf_res is et

et_lv = etuple(add, a_lv, 2)
assert reify(et_lv[1:], {})._parent is et_lv

# Reify a logic variable to another logic variable
assert reify(et_lv[1:], {a_lv: b_lv})._parent is et_lv

# TODO: We could propagate the parent etuple when a sub-etuple is `cons`ed
# with logic variables.
# et_1 = et[2:]
# et_2 = cons(b_lv, et_1)
# assert et_2._parent is et
# assert reify(et_2, {a_lv: 1})._parent is et