sim_lib_logic/unify.rs
1//! Standalone unification entry point over the kernel `Expr` graph.
2//!
3//! [`unify_exprs`] unifies two terms once and reports the result as a kernel
4//! `ShapeMatch`, the same accept/reject surface used by the `Shape` protocol;
5//! see the [`README`](https://docs.rs/sim-runtime).
6
7use sim_kernel::{Cx, Expr, Result, ShapeMatch};
8
9use crate::{
10 env::LogicEnv,
11 model::{LogicConfig, OccursCheck},
12};
13
14/// Unifies two expressions and reports the result as a kernel `ShapeMatch`.
15///
16/// On success the returned match is accepting and its captures hold the
17/// variable bindings; on a structural mismatch it is a rejecting match. The
18/// occurs-check policy comes from `config`.
19///
20/// # Examples
21///
22/// ```
23/// use std::sync::Arc;
24/// use sim_kernel::{Cx, DefaultFactory, EagerPolicy, Expr, Symbol};
25/// use sim_lib_logic::{LogicConfig, unify_exprs};
26///
27/// let mut cx = Cx::new(Arc::new(EagerPolicy), Arc::new(DefaultFactory));
28/// let left = Expr::List(vec![
29/// Expr::Symbol(Symbol::new("point")),
30/// Expr::Local(Symbol::new("x")),
31/// ]);
32/// let right = Expr::List(vec![
33/// Expr::Symbol(Symbol::new("point")),
34/// Expr::Symbol(Symbol::new("origin")),
35/// ]);
36/// let matched = unify_exprs(&mut cx, &LogicConfig::default(), &left, &right).unwrap();
37/// assert!(matched.accepted);
38/// ```
39pub fn unify_exprs(
40 cx: &mut Cx,
41 config: &LogicConfig,
42 left: &Expr,
43 right: &Expr,
44) -> Result<ShapeMatch> {
45 let mut env = LogicEnv::new();
46 let accepted = env.unify(left, right, occurs_check(config))?;
47 if accepted {
48 env.as_shape_match(cx)
49 } else {
50 Ok(sim_kernel::ShapeMatch::reject("unification failed"))
51 }
52}
53
54pub(crate) fn occurs_check(config: &LogicConfig) -> OccursCheck {
55 config.occurs_check
56}