[−][src]Trait egg::Applier
The righthand side of a Rewrite
.
An Applier
is anything that can do something with a
substitition (WildMap
). This allows you to implement rewrites
that determine when and how to respond to a match using custom
logic, including access to the Metadata
of an EClass
.
Notably, Pattern
implements Applier
, which suffices in
most cases.
Additionally, egg
provides ConditionalApplier
to stack
Condition
s onto an Applier
, which in many cases can save
you from having to implement your own applier.
Example
use egg::{rewrite as rw, *}; define_language! { enum Math { Num(i32), Add = "+", Mul = "*", Symbol(String), } } // Our metadata in this case will be size of the smallest // represented expression in the eclass. #[derive(Debug)] struct Meta { size: usize, } type EGraph = egg::EGraph<Math, Meta>; impl Metadata<Math> for Meta { type Error = (); fn merge(&self, other: &Self) -> Self { let size = self.size.min(other.size); Meta { size } } fn make(enode: ENode<Math, &Self>) -> Self { let size = AstSize.cost(&enode.map_children(|c| c.size)); Meta { size } } } let rules = &[ rw!("commute-add"; "(+ ?a ?b)" => "(+ ?b ?a)"), rw!("commute-mul"; "(* ?a ?b)" => "(* ?b ?a)"), rw!("add-0"; "(+ ?a 0)" => "?a"), rw!("mul-0"; "(* ?a 0)" => "0"), rw!("mul-1"; "(* ?a 1)" => "?a"), // the rewrite macro parses the rhs as a single token tree, so // we wrap it in braces (parens work too). rw!("funky"; "(+ ?a (* ?b ?c))" => { Funky { a: "?a".parse().unwrap(), b: "?b".parse().unwrap(), c: "?c".parse().unwrap(), }}), ]; struct Funky { a: QuestionMarkName, b: QuestionMarkName, c: QuestionMarkName, } impl Applier<Math, Meta> for Funky { fn apply_one(&self, egraph: &mut EGraph, matched_id: Id, mapping: &WildMap) -> Vec<Id> { let a: Id = mapping[&self.a][0]; // In a custom Applier, you can inspect the Metadata, // which is powerful combination! let meta_for_a: &Meta = &egraph[a].metadata; if meta_for_a.size > 50 { println!("Too big! Not doing anything"); vec![] } else { // we're going to manually add: // (+ (+ ?a 0) (* (+ ?b 0) (+ ?c 0))) // to be unified with the original: // (+ ?a (* ?b ?c )) let b: Id = mapping[&self.b][0]; let c: Id = mapping[&self.c][0]; let zero = egraph.add(enode!(Math::Num(0))); let a0 = egraph.add(enode!(Math::Add, a, zero)); let b0 = egraph.add(enode!(Math::Add, b, zero)); let c0 = egraph.add(enode!(Math::Add, c, zero)); let b0c0 = egraph.add(enode!(Math::Mul, b0, c0)); let a0b0c0 = egraph.add(enode!(Math::Add, a0, b0c0)); // NOTE: we just return the id according to what we // want unified with matched_id. The `apply_matches` // method actually does the union, _not_ `apply_one`. vec![a0b0c0] } } } let start = "(+ x (* y z))".parse().unwrap(); SimpleRunner::default().run_expr(start, rules);
Required methods
fn apply_one(
&self,
egraph: &mut EGraph<L, M>,
eclass: Id,
mapping: &WildMap
) -> Vec<Id>
&self,
egraph: &mut EGraph<L, M>,
eclass: Id,
mapping: &WildMap
) -> Vec<Id>
Apply a single substitition.
An Applier
should only add things to the egraph here,
not union them with the id eclass
.
That is the responsibility of the apply_matches
method.
The eclass
parameter allows the implementer to inspect the
eclass where the match was found if they need to.
This should return a list of Id
s of things you'd like to
be unioned with eclass
. There can be zero, one, or many.
Provided methods
fn apply_matches(
&self,
egraph: &mut EGraph<L, M>,
matches: &[SearchMatches]
) -> Vec<Id>
&self,
egraph: &mut EGraph<L, M>,
matches: &[SearchMatches]
) -> Vec<Id>
Implementors
impl<C, A, L, M> Applier<L, M> for ConditionalApplier<C, A> where
L: Language,
M: Metadata<L>,
A: Applier<L, M>,
C: Condition<L, M>,
[src]
L: Language,
M: Metadata<L>,
A: Applier<L, M>,
C: Condition<L, M>,