pub struct Rule { /* private fields */ }Expand description
A named rewrite rule lhs → rhs over expressions of one Context.
Symbols in lhs whose names end in _ are wildcards; a name ending
in __ is a sequence wildcard that absorbs the remaining terms of
an Add/Mul (see the Ex::rewrite docs). The right-hand side is
either a template expression (wildcards are substituted) or a closure
receiving the Bindings.
Rules are Clone + Send + Sync.
§Examples
use symplex::prelude::*;
use symplex::macros::Rule;
let ctx = Context::new();
let (x, a) = (ctx.symbol("x"), ctx.symbol("a_"));
// Template rule: exp(ln(a_)) → a_
let r = Rule::new("exp_ln", &a.ln().exp(), &a);
assert_eq!(r.apply(&x.ln().exp()), Some(x.clone()));
assert_eq!(r.apply(&x.exp()), None);
// Guarded rule: only fire when the bound value is a number.
let g = Rule::new_with_guard("sin_num", &a.sin(), &ctx.int(0), |b| {
b.get("a_").is_some_and(|v| v.expr_type() == ExprType::Number)
});
assert!(g.apply(&x.sin()).is_none());
assert_eq!(g.apply(&ctx.int(7).sin()), Some(ctx.int(0)));Implementations§
Source§impl Rule
impl Rule
Sourcepub fn try_new(
name: impl Into<String>,
lhs: &Ex,
rhs: &Ex,
) -> Result<Rule, SymplexError>
pub fn try_new( name: impl Into<String>, lhs: &Ex, rhs: &Ex, ) -> Result<Rule, SymplexError>
Like new, but returns an error when rhs mentions
a wildcard that is not bound by lhs, or when lhs has no
structure at all (a bare wildcard would match everything).
§Examples
use symplex::prelude::*;
use symplex::macros::Rule;
let ctx = Context::new();
let (a, b) = (ctx.symbol("a_"), ctx.symbol("b_"));
assert!(Rule::try_new("bad", &a.sin(), &b).is_err());
assert!(Rule::try_new("ok", &a.sin(), &a).is_ok());Sourcepub fn new_with_guard(
name: impl Into<String>,
lhs: &Ex,
rhs: &Ex,
guard: impl Fn(&Bindings) -> bool + Send + Sync + 'static,
) -> Rule
pub fn new_with_guard( name: impl Into<String>, lhs: &Ex, rhs: &Ex, guard: impl Fn(&Bindings) -> bool + Send + Sync + 'static, ) -> Rule
Build a template rule with a guard: the rewrite fires only when
guard(&bindings) returns true.
The guard runs without holding the context lock, so it may call
any Ex method (e.g. is_positive(), is_number()).
§Panics
Panics if lhs and rhs belong to different contexts.
Sourcepub fn new_fn(
name: impl Into<String>,
lhs: &Ex,
f: impl Fn(&Bindings) -> Option<Ex> + Send + Sync + 'static,
) -> Rule
pub fn new_fn( name: impl Into<String>, lhs: &Ex, f: impl Fn(&Bindings) -> Option<Ex> + Send + Sync + 'static, ) -> Rule
Build a rule whose right-hand side is computed by a closure.
Returning None from the closure means “does not apply” (the next
match / rule is tried). The returned expression must belong to
the same context as lhs.
§Examples
use symplex::prelude::*;
use symplex::macros::{Rule, RuleSet};
let ctx = Context::new();
let (x, a) = (ctx.symbol("x"), ctx.symbol("a_"));
// Evaluate ln of perfect powers of e: ln(exp(a_)) → a_ only if a_ is a number.
let r = Rule::new_fn("ln_exp_num", &a.exp().ln(), |b| {
let v = b.get("a_")?;
(v.expr_type() == ExprType::Number).then(|| v.clone())
});
let rules = RuleSet::from_rules(vec![r]);
assert_eq!(format!("{}", ctx.int(3).exp().ln().rewrite(&rules)), "3");
assert_eq!(format!("{}", x.exp().ln().rewrite(&rules)), "ln(exp(x))");Sourcepub fn from_macro_rule(ctx: &Context, rule: Rule) -> Rule
pub fn from_macro_rule(ctx: &Context, rule: Rule) -> Rule
Wrap an arena-level rule produced by the rule!
macro (built inside ctx.with_arena_mut(|arena| ...)).
§Examples
use symplex::prelude::*;
use symplex::macros::{Rule, RuleSet};
let ctx = Context::new();
let x = ctx.symbol("x");
let raw = ctx.with_arena_mut(|arena| rule!(arena, "pyth", sin(w_)^2 + cos(w_)^2 => 1));
let rule = Rule::from_macro_rule(&ctx, raw);
let rules = RuleSet::from_rules(vec![rule]);
let expr = &x.sin().powi(2) + &x.cos().powi(2) + 2;
assert_eq!(format!("{}", expr.rewrite(&rules)), "3");Sourcepub fn wildcards(&self) -> Vec<String>
pub fn wildcards(&self) -> Vec<String>
Names of the wildcards bound by this rule’s left-hand side.
Trait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for Rule
impl !UnwindSafe for Rule
impl Freeze for Rule
impl Send for Rule
impl Sync for Rule
impl Unpin for Rule
impl UnsafeUnpin for Rule
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more