def unify_term(u, v, s): u_op, u_args = operator(u), arguments(u) v_op, v_args = operator(v), arguments(v) s = unify(u_op, v_op, s) if s is not False: s = unify(u_args, v_args, s) return s
def test_graph_applyo_reverse(): """Test `graph_applyo` in "reverse" (i.e. specify the reduced form and generate the un-reduced form).""" q_lv = var('q') test_res = run(2, q_lv, fixedp_graph_applyo(math_reduceo, q_lv, 5)) assert test_res == (etuple(log, etuple(exp, 5)), etuple(log, etuple(exp, etuple(log, etuple(exp, 5))))) assert all(e.eval_obj == 5.0 for e in test_res) # Make sure we get some variety in the results test_res = run(2, q_lv, fixedp_graph_applyo(math_reduceo, q_lv, etuple(mul, 2, 5))) assert test_res == ( # Expansion of the term's root etuple(add, 5, 5), # Two step expansion at the root etuple(log, etuple(exp, etuple(add, 5, 5))), # Expansion into a sub-term # etuple(mul, 2, etuple(log, etuple(exp, 5))) ) assert all(e.eval_obj == 10.0 for e in test_res) r_lv = var('r') test_res = run(4, [q_lv, r_lv], fixedp_graph_applyo(math_reduceo, q_lv, r_lv)) expect_res = ([etuple(add, 1, 1), etuple(mul, 2, 1)], [ etuple(log, etuple(exp, etuple(add, 1, 1))), etuple(mul, 2, 1) ], [etuple(), etuple()], [ etuple(add, etuple(mul, 2, 1), etuple(add, 1, 1)), etuple(mul, 2, etuple(mul, 2, 1)) ]) assert list( unify(a1, a2) and unify(b1, b2) for [a1, b1], [a2, b2] in zip(test_res, expect_res))
def test_unify_Op(): # These `Op`s expand into `ExpressionTuple`s op1 = CustomOp(1) op2 = CustomOp(1) # `Op`, `Op` s = unify(op1, op2) assert s == {} # `ExpressionTuple`, `Op` s = unify(etuplize(op1), op2) assert s == {} # These `Op`s don't expand into `ExpressionTuple`s op1_np = CustomOpNoProps(1) op2_np = CustomOpNoProps(1) s = unify(op1_np, op2_np) assert s == {} # Same, but this one also doesn't implement `__eq__` op1_np_neq = CustomOpNoPropsNoEq(1) s = unify(op1_np_neq, etuplize(op1)) assert s is False
def _proofs_of(cls, term): # If term contains any variables then we rename them here so that they # don't collide with variable names used in this proof. term = rename_variables(term, '__parent__.') for rule in cls.get_rules(): variables = unify(term, rule.conclusion) if variables is False: continue if not rule.premises: yield Proof(rule, variables) continue # If we reach here it means that there are premises to prove. reified_premises = [reify(x, variables) for x in rule.premises] for premise_proofs in cls._proofs_of_many(reified_premises): candiate_variables = variables for (premise, premise_proof) in zip(reified_premises, premise_proofs): candiate_variables = unify(premise, premise_proof.conclusion, candiate_variables) if candiate_variables is False: break else: yield Proof(rule, candiate_variables, premise_proofs)
def decode(code): match = unification.unify(inl_pattern, code) if match: return (True, decode_inl(match[x])) match = unification.unify(inr_pattern, code) if match: return (False, decode_inr(match[x])) raise TypeError(code)
def test_unify_binary(): with interpretation(lazy): pattern = Variable('a', reals()) + Number(2.) * Variable('b', reals()) expr = Number(1.) + Number(2.) * (Number(3.) - Number(4.)) subs = unify(pattern, expr) print(subs, pattern(**{k.name: v for k, v in subs.items()})) assert subs is not False with interpretation(unify_interpreter): assert unify((pattern, ), (expr, )) is not False
def test_operator(): s = unify(TFlowMetaOperator(var('a'), var('b')), mt.add) assert s[var('a')] == mt.add.op_def assert s[var('b')] == mt.add.node_def add_mt = reify(TFlowMetaOperator(var('a'), var('b')), s) assert add_mt == mt.add assert unify(mt.mul, mt.matmul) is False assert unify(mt.mul.op_def, mt.matmul.op_def) is False
def old_get_landmarks(start: Iterable[Term], goals: Iterable[Term], actions: Iterable[Action]): action_list = [x for x in actions] action_match = [] for action in action_list: unifiable_goals = unifiable(goals) for adds in itertools.combinations(action.add, len(goals)): unifiable_adds = unifiable(list(adds)) if unify(unifiable_goals, unifiable_adds): # does it also unify with preconditions: found_match = False for pres in itertools.combinations(action.requirements, len(goals)): if unify(unifiable_goals, unifiable(list(pres))): found_match = True break if not found_match: action_match.append(action) break graph = [] for goal in goals: # find all actions that directly have the goal as a postcondition for action in actions: for add_rule in action.add: if terms_equal(add_rule, goal): action_match.append(action) break # see if they are already in the graph pass # add them to the graph graph.append(action_match) # find any precondition that all goals share landmarks = set_intersect([ set([CustomTerm(y) for y in x.requirements]) for x in action_match ]) # see if they are already in the graph pass # add to the graph graph.append(landmarks) return graph
def test_ConstrainedState(): a_lv, b_lv = var(), var() ks = ConstrainedState() assert repr(ks) == "ConstrainedState({}, {})" assert ks == {} assert {} == ks assert not ks == {a_lv: 1} assert not ks == ConstrainedState({a_lv: 1}) assert unify(1, 1, ks) is not None assert unify(1, 2, ks) is False assert unify(b_lv, a_lv, ks) assert unify(a_lv, b_lv, ks) assert unify(a_lv, b_lv, ks) # Now, try that with a constraint (that's never used). ks.constraints[DisequalityStore] = DisequalityStore({a_lv: {1}}) assert not ks == {a_lv: 1} assert not ks == ConstrainedState({a_lv: 1}) assert unify(1, 1, ks) is not None assert unify(1, 2, ks) is False assert unify(b_lv, a_lv, ks) assert unify(a_lv, b_lv, ks) assert unify(a_lv, b_lv, ks) ks = ConstrainedState( {a_lv: 1}, constraints={DisequalityStore: DisequalityStore({b_lv: {1}})} ) ks_2 = ks.copy() assert ks == ks_2 assert ks is not ks_2 assert ks.constraints is not ks_2.constraints assert ks.constraints[DisequalityStore] is not ks_2.constraints[DisequalityStore] assert ( ks.constraints[DisequalityStore].lvar_constraints[b_lv] == ks_2.constraints[DisequalityStore].lvar_constraints[b_lv] ) assert ( ks.constraints[DisequalityStore].lvar_constraints[b_lv] is not ks_2.constraints[DisequalityStore].lvar_constraints[b_lv] )
def test_basic_unify_reify(): # Test reification with manually constructed replacements a = tf.compat.v1.placeholder(tf.float64, name='a') x_l = var('x_l') a_reif = reify(x_l, {x_l: mt(a)}) assert a_reif.obj is not None # Confirm that identity is preserved (i.e. that the underlying object # was properly tracked and not unnecessarily reconstructed) assert a == a_reif.reify() test_expr = mt.add(tf.constant(1, dtype=tf.float64), mt.mul(tf.constant(2, dtype=tf.float64), x_l)) test_reify_res = reify(test_expr, {x_l: a}) test_base_res = test_reify_res.reify() assert isinstance(test_base_res, tf.Tensor) with tf.Graph().as_default(): a = tf.compat.v1.placeholder(tf.float64, name='a') expected_res = tf.add(tf.constant(1, dtype=tf.float64), tf.multiply(tf.constant(2, dtype=tf.float64), a)) assert_ops_equal(test_base_res, expected_res) # Simply make sure that unification succeeds meta_expected_res = mt(expected_res) s_test = unify(test_expr, meta_expected_res, {}) assert len(s_test) == 3 assert reify(test_expr, s_test) == meta_expected_res
def neq_goal(S): nonlocal u, v u_rf, v_rf = reify((u, v), S) # Get the unground logic variables that would unify the two objects; # these are all the logic variables that we can't let unify. s_uv = unify(u_rf, v_rf, {}) if s_uv is False: # They don't unify and have no unground logic variables, so the # constraint is immediately satisfied. yield S return elif not s_uv: # They already unify, but with no unground logic variables, so we # have an immediate violation of the constraint. return if not isinstance(S, ConstrainedState): S = ConstrainedState(S) cs = S.constraints.setdefault(DisequalityStore, DisequalityStore()) for lvar, obj in s_uv.items(): cs.add(lvar, obj) # We need to check the current state for validity. if cs.post_unify_check(S.data): yield S
def post_unify_check(self, lvar_map, lvar=None, value=None, old_state=None): for lv_key, constraints in list(self.lvar_constraints.items()): lv = reify(lv_key, lvar_map) constraints_rf = reify(tuple(constraints), lvar_map) for cs in constraints_rf: s = unify(lv, cs, {}) if s is not False and not s: # They already unify, but with no unground logic variables, # so we have an immediate violation of the constraint. return False elif s is False: # They don't unify and have no unground logic variables, so # the constraint is immediately satisfied and there's no # reason to continue checking this constraint. constraints.discard(cs) else: # They unify when/if the unifications in `s` are made, so # let's add these as new constraints. for k, v in s.items(): self.add(k, v) if len(constraints) == 0: # This logic variable has no more unground constraints, so # remove it. del self.lvar_constraints[lv_key] return True
def get_fresh(action: Action): add_objects = [] for add in action.add: if isinstance(add, Term) and len(add.literals) == 1: add_objects.append(add) add_props = defaultdict(list) for add in action.add: if isinstance(add, Term) and len(add.literals) != 1: add_props[add.literals[0]].append(add) req_objects = [] for req in action.requirements: if isinstance(req, Term) and len(req.literals) == 1: req_objects.append(req) req_props = defaultdict(list) for req in action.requirements: if isinstance(req, Term) and len(req.literals) != 1: req_props[req.literals[0]].append(req) null_props = [] for add_object in add_objects: for req_object in req_objects: if add_object.predicate == req_object.predicate: # find the freshness for req_prop in req_props[req_object.literals[0]]: # does it unify with an add prop? for add_prop in add_props[add_object.literals[0]]: if unify(make_unifiable(convert_value_var_to_static(add_prop)), make_unifiable(convert_value_var_to_static(req_prop))): # then nullify the add prop null_props.append(add_prop) return list(set(action.add) - set(null_props))
def unification(): while True: print('Enter two terms.') term_1 = input('Enter the first term: ') result = analyze_term(term_1, []) if not result[0]: print('invalid term, please try again.') print(result[1]) print('press a key to continue') input() continue term_2 = input('Enter the second term: ') analyze_term(term_2, []) if not result[0]: print('invalid term, please try again.') print(result[1]) print('press a key to continue') input() continue result = unify(term_1, term_2, []) print('Result:- \tO = ' + stringify(result) if result is not None else 'Unification Failed.') print('Note: the pair (x, y) is read as: substitute every occurence of y by x.') choice = input('Press c to return to Main Menu, or press any other key to exit: ') if choice == 'c' or choice == 'C': return False else: return True
def decode(code): match = unification.unify(pair_pattern, code) if not match: raise TypeError(code) x_value = decode_fst(match[x]) y_value = decode_snd(match[y]) return (x_value, y_value)
def unify_node(self, contents) -> Union[Node, None]: for node in self.nodes: unification = unify(make_unifiable(contents), make_unifiable(node.content)) if unification: return node, unification return None, None
def decode(code): if code is lib.none: return None match = unification.unify(some_pattern, code) if not match: raise TypeError(code) return (decode_item(match[item_var]),)
def test_disequality_basic(): a_lv, b_lv = var(), var() ks = ConstrainedState() de = DisequalityStore({a_lv: {1}}) ks.constraints[DisequalityStore] = de assert unify(a_lv, 1, ks) is False ks = unify(a_lv, b_lv, ks) assert unify(b_lv, 1, ks) is False res = list(lconj(neq({}, 1))({})) assert len(res) == 1 res = list(lconj(neq(1, {}))({})) assert len(res) == 1 res = list(lconj(neq({}, {}))({})) assert len(res) == 0 res = list(lconj(neq(a_lv, 1))({})) assert len(res) == 1 assert isinstance(res[0], ConstrainedState) assert res[0].constraints[DisequalityStore].lvar_constraints[a_lv] == {1} res = list(lconj(neq(1, a_lv))({})) assert len(res) == 1 assert isinstance(res[0], ConstrainedState) assert res[0].constraints[DisequalityStore].lvar_constraints[a_lv] == {1} res = list(lconj(neq(a_lv, 1), neq(a_lv, 2), neq(a_lv, 1))({})) assert len(res) == 1 assert isinstance(res[0], ConstrainedState) assert res[0].constraints[DisequalityStore].lvar_constraints[a_lv] == {1, 2} res = list(lconj(neq(a_lv, 1), eq(a_lv, 2))({})) assert len(res) == 1 assert isinstance(res[0], ConstrainedState) # The constrained variable is already ground and satisfies the constraint, # so it should've been removed from the store assert a_lv not in res[0].constraints[DisequalityStore].lvar_constraints assert res[0][a_lv] == 2 res = list(lconj(eq(a_lv, 1), neq(a_lv, 1))({})) assert res == []
def test_unify_Constant(): # Make sure `Constant` unification works c1_at = at.as_tensor(np.r_[1, 2]) c2_at = at.as_tensor(np.r_[1, 2]) # `Constant`, `Constant` s = unify(c1_at, c2_at) assert s == {}
def test_unify(): q_lv = var() op = SomeMetaOp() a_args = (1, 2) a = SomeMetaVariable(op, a_args, obj=SomeType(1, 2)) b = SomeMetaVariable(op, q_lv) s = unify(a, b) assert s is not False assert s[q_lv] is a_args obj = reify(b, s) assert obj == a r_lv = var() b = SomeMetaVariable(op, q_lv, obj=r_lv) s = unify(a, b) assert s is not False assert s[r_lv] is a.obj assert car(a) == rator(a) == op assert isinstance(cdr(a), ExpressionTuple) assert isinstance(rands(a), ExpressionTuple) assert cdr(a) == rands(a) == a_args a = SomeMetaVariable(op, ()) with pytest.raises(ConsError): cdr(a) with pytest.raises(ConsError): rands(a) op = SomeOtherMetaOp() a = SomeMetaVariable(op, ()) with pytest.raises(ConsError): car(a) with pytest.raises(ConsError): rator(a)
def unify_ConstrainedState(u, v, S): if S.pre_unify_checks(u, v): s = unify(u, v, S.data) if s is not False: S = S.post_unify_checks(s, u, v) if S is not False: return S return False
def decode(code): result = [] while code is not lib.nil: match = unification.unify(cons_pattern, code) if not match: raise TypeError(code) result.append(decode_item(match[head])) code = match[tail] return result
def test_map_anyo_misc(): q_lv = var("q") res = run(0, q_lv, map_anyo(eq, [1, 2, 3], [1, 2, 3])) # TODO: Remove duplicate results assert len(res) == 7 res = run(0, q_lv, map_anyo(eq, [1, 2, 3], [1, 3, 3])) assert len(res) == 0 def one_to_threeo(x, y): return conde([eq(x, 1), eq(y, 3)]) res = run(0, q_lv, map_anyo(one_to_threeo, [1, 2, 4, 1, 4, 1, 1], q_lv)) assert res[0] == [3, 2, 4, 3, 4, 3, 3] assert (len( run(4, q_lv, map_anyo(math_reduceo, [etuple(mul, 2, var("x"))], q_lv))) == 0) test_res = run(4, q_lv, map_anyo(math_reduceo, [etuple(add, 2, 2), 1], q_lv)) assert test_res == ([etuple(mul, 2, 2), 1], ) test_res = run(4, q_lv, map_anyo(math_reduceo, [1, etuple(add, 2, 2)], q_lv)) assert test_res == ([1, etuple(mul, 2, 2)], ) test_res = run(4, q_lv, map_anyo(math_reduceo, q_lv, var("z"))) assert all(isinstance(r, list) for r in test_res) test_res = run(4, q_lv, map_anyo(math_reduceo, q_lv, var("z"), tuple)) assert all(isinstance(r, tuple) for r in test_res) x, y, z = var(), var(), var() def test_bin(a, b): return conde([eq(a, 1), eq(b, 2)]) res = run(10, (x, y), map_anyo(test_bin, x, y, null_type=tuple)) exp_res_form = ( ((1, ), (2, )), ((x, 1), (x, 2)), ((1, 1), (2, 2)), ((x, y, 1), (x, y, 2)), ((1, x), (2, x)), ((x, 1, 1), (x, 2, 2)), ((1, 1, 1), (2, 2, 2)), ((x, y, z, 1), (x, y, z, 2)), ((1, x, 1), (2, x, 2)), ((x, 1, y), (x, 2, y)), ) for a, b in zip(res, exp_res_form): s = unify(a, b) assert s is not False assert all(isvar(i) for i in reify((x, y, z), s))
def test_unifiable_with_term(): add = Op('add') t = MyTerm(add, (1, 2)) assert arguments(t) == (1, 2) assert operator(t) == add assert term(operator(t), arguments(t)) == t x = var('x') assert unify(MyTerm(add, (1, x)), MyTerm(add, (1, 2)), {}) == {x: 2}
def test_sexp_unify_reify(): """Make sure we can unify and reify etuples/S-exps.""" # Unify `A . (x + y)`, for `x`, `y` logic variables A = tf.compat.v1.placeholder(tf.float64, name="A", shape=tf.TensorShape([None, None])) x = tf.compat.v1.placeholder(tf.float64, name="x", shape=tf.TensorShape([None, 1])) y = tf.compat.v1.placeholder(tf.float64, name="y", shape=tf.TensorShape([None, 1])) z = tf.matmul(A, tf.add(x, y)) z_sexp = etuplize(z, shallow=False) # Let's just be sure that the original TF objects are preserved assert z_sexp[1].reify() == A assert z_sexp[2][1].reify() == x assert z_sexp[2][2].reify() == y A_lv, x_lv, y_lv = var(), var(), var() dis_pat = etuple( TFlowMetaOperator(mt.matmul.op_def, var()), A_lv, etuple(TFlowMetaOperator(mt.add.op_def, var()), x_lv, y_lv), ) s = unify(dis_pat, z_sexp, {}) assert s[A_lv] == mt(A) assert s[x_lv] == mt(x) assert s[y_lv] == mt(y) # Now, we construct a graph that reflects the distributive property and # reify with the substitutions from the un-distributed form out_pat = etuple(mt.add, etuple(mt.matmul, A_lv, x_lv), etuple(mt.matmul, A_lv, y_lv)) z_dist = reify(out_pat, s) # Evaluate the tuple-expression and get a meta object/graph z_dist_mt = z_dist.eval_obj # If all the logic variables were reified, we should be able to # further reify the meta graph and get a concrete TF graph z_dist_tf = z_dist_mt.reify() assert isinstance(z_dist_tf, tf.Tensor) # Check the first part of `A . x + A . y` (i.e. `A . x`) assert z_dist_tf.op.inputs[0].op.inputs[0] == A assert z_dist_tf.op.inputs[0].op.inputs[1] == x # Now, the second, `A . y` assert z_dist_tf.op.inputs[1].op.inputs[0] == A assert z_dist_tf.op.inputs[1].op.inputs[1] == y
def test_unify_Type(): t1 = TensorType(np.float64, (True, False)) t2 = TensorType(np.float64, (True, False)) # `Type`, `Type` s = unify(t1, t2) assert s == {} # `Type`, `ExpressionTuple` s = unify(t1, etuple(TensorType, "float64", (1, None))) assert s == {} from aesara.scalar.basic import Scalar st1 = Scalar(np.float64) st2 = Scalar(np.float64) s = unify(st1, st2) assert s == {}
def decode_num(code): result = 0 while True: if code is lib.zero: return result match = unification.unify(_succ_pattern, code) if not match: raise TypeError(code) result += 1 code = match[_pred_var]
def compute_mgu(constraints): def varify(x): if isinstance(x, TVar): return unification.var(x) return x constraints_l = tuple([varify(c[0]) for c in constraints]) constraints_r = tuple([varify(c[1]) for c in constraints]) mgu = unification.unify(constraints_l, constraints_r) return mgu
def test_ConstrainedVar(): cvar = ConstrainedVar(lambda x: isinstance(x, str)) assert repr(cvar).startswith("ConstrainedVar(") assert repr(cvar).endswith(f", {cvar.token})") s = unify(cvar, 1) assert s is False s = unify(1, cvar) assert s is False s = unify(cvar, "hi") assert s[cvar] == "hi" s = unify("hi", cvar) assert s[cvar] == "hi" x_lv = var() s = unify(cvar, x_lv) assert s == {cvar: x_lv} s = unify(cvar, x_lv, {x_lv: "hi"}) assert s[cvar] == "hi" s = unify(x_lv, cvar, {x_lv: "hi"}) assert s[cvar] == "hi" s_orig = {cvar: "hi", x_lv: "hi"} s = unify(x_lv, cvar, s_orig) assert s == s_orig s_orig = {cvar: "hi", x_lv: "bye"} s = unify(x_lv, cvar, s_orig) assert s is False x_at = at.vector("x") y_at = at.vector("y") op1_np = CustomOpNoProps(1) r_at = etuple(op1_np, x_at, y_at) def constraint(x): return isinstance(x, tuple) a_lv = ConstrainedVar(constraint) res = reify(etuple(op1_np, a_lv), {a_lv: r_at}) assert res[1] == r_at
def search(): if request.method == 'POST': qu = request.form['word'] qu = qu.lower() query = unify(qu) try: res = js[query] return render_template('search.html', res=res) except KeyError: return render_template('search.html', comment='There is no such entry') return render_template('search.html')
def unify_nodes(self, combine_func): unifications = defaultdict(set) for node1, node2 in itertools.combinations(self.nodes, 2): assert node1 != node2 unity = unify(make_unifiable(node1.content), make_unifiable(node2.content)) if unity or unity == {}: unifications[node1].add(node2) for node1, node_set in unifications.items(): for node2 in node_set: if node1 in self.nodes and node2 in self.nodes: self.combine_nodes(node1, node2, combine_func)
def goal(substitution): args2 = reify(args, substitution) subsets = [self.index[key] for key in enumerate(args) if key in self.index] if subsets: # we are able to reduce the pool early facts = intersection(*sorted(subsets, key=len)) else: facts = self.facts for fact in facts: unified = unify(fact, args2, substitution) if unified != False: yield merge(unified, substitution)
def test_walko_reverse(): """Test `walko` in "reverse" (i.e. specify the reduced form and generate the un-reduced form).""" # noqa: E501 q_lv = var("q") test_res = run(2, q_lv, term_walko(math_reduceo, q_lv, 5)) assert test_res == ( etuple(log, etuple(exp, 5)), etuple(log, etuple(exp, etuple(log, etuple(exp, 5)))), ) assert all(e.eval_obj == 5.0 for e in test_res) # Make sure we get some variety in the results test_res = run(2, q_lv, term_walko(math_reduceo, q_lv, etuple(mul, 2, 5))) assert test_res == ( # Expansion of the term's root etuple(add, 5, 5), # Expansion in the term's arguments etuple(mul, etuple(log, etuple(exp, 2)), etuple(log, etuple(exp, 5))), # Two step expansion at the root # etuple(log, etuple(exp, etuple(add, 5, 5))), # Expansion into a sub-term # etuple(mul, 2, etuple(log, etuple(exp, 5))) ) assert all(e.eval_obj == 10.0 for e in test_res) r_lv = var("r") test_res = run(4, [q_lv, r_lv], term_walko(math_reduceo, q_lv, r_lv)) expect_res = ( [etuple(add, 1, 1), etuple(mul, 2, 1)], [etuple(log, etuple(exp, etuple(add, 1, 1))), etuple(mul, 2, 1)], [etuple(), etuple()], [ etuple(add, etuple(mul, 2, 1), etuple(add, 1, 1)), etuple(mul, 2, etuple(mul, 2, 1)), ], ) assert list( unify(a1, a2) and unify(b1, b2) for [a1, b1], [a2, b2] in zip(test_res, expect_res))
def test_unifiable_with_term(): add = Operator("add") t = Node(add, (1, 2)) assert arguments(t) == (1, 2) assert operator(t) == add assert term(operator(t), arguments(t)) == t x = var() s = unify(Node(add, (1, x)), Node(add, (1, 2)), {}) assert s == {x: 2} assert reify(Node(add, (1, x)), s) == Node(add, (1, 2))
def concat_goal(S): nonlocal a, b, out a_rf, b_rf, out_rf = reify((a, b, out), S) if isinstance(a_rf, str) and isinstance(b_rf, str): S_new = unify(out_rf, a_rf + b_rf, S) if S_new is not False: yield S_new return elif isinstance(a_rf, (Var, str)) and isinstance(b_rf, (Var, str)): yield S
def _nullo(s): _s = reify(l, s) if isvar(_s): yield unify(_s, None, s) elif is_null(_s): yield s
def test_lcons(): assert unify(LCons(1, ()), (x, )) == {x: 1} assert unify(LCons(1, (x, )), (x, y)) == {x: 1, y: 1} assert unify((x, y), LCons(1, (x, ))) == {x: 1, y: 1} assert unify(LCons(x, y), ()) == False assert list(LCons(1, LCons(2, x))) == [1, 2]
def _lcons_unify(lcons, t, s): if len(t) == 0: return False return unify((lcons.head, lcons.tail), (t[0], t[1:]), s)
def goal_eq(s): result = unify(u, v, s) if result is not False: yield result