Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Pattern matching with Box layers

I am trying to solve the expression problem in Rust. I have defined a sum type of terms:

#[derive(Clone, Debug, PartialEq)]
pub enum Term {
    True,
    False,
    Not(Box<Term>),
    ...
}

The compiler and documentation say Box is needed for recursive terms because a structure cannot contain itself (infinite regress), and just plain &Term would not be enough to establish that a term owns its subterms. Okay, so far so good.

Now I’m trying to write a function that simplifies terms according to the definitions of the operators, e.g. not true = false:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

impl Term {
    pub fn simplify(self) -> Term {
        let a = self.map(Term::simplify);
        match a {
            Term::Not(Box(Term::True)) => Term::False,
            _ => a,
        }
    }

    pub fn map(self, f: fn(Term) -> Term) -> Term {
        match self {
            Term::True
            | Term::False => self,
            Term::Not(a) => Term::Not(Box::new(a.map(f))),
            _ => panic!(),
        }
    }
}

but the compiler doesn’t like any version of it that I have tried so far.

Term::Not(Term::True) is not valid because a Box needs to go in between.

Term::Not(Box::new(Term::True)) is valid when making a term, but not as a pattern match expression (which cannot contain function calls).

Term::Not(Box(Term::True)) is not valid either.

What is the right way to do this in Rust?

>Solution :

The compiler gives the following error:
cannot match against a tuple struct which contains private fields.
Okay, so let’s look for the definition of Box (I removed the trait bounds for simplicity):

pub struct Box<_>(Unique<T>, A);

That looks like the tuple in the error message. But it also looks like the inner values are not public (that’s the error), so you can’t construct the box like this (Box(Term::True)).

What can we do?
You could use the nightly feature box_patterns to create the box:

match a {
    Term::Not(box Term::True) => Term::False,
    _ => a,
}

Playground

Or, we try to extract the value out of the box (here in boxed_value) via dereferencing it and then check the inner value:

*boxed_value == Term::True

You can use this in combination with if guards in your match:

match a {
    Term::Not(content) if *content == Term::True => Term::False,
    _ => a,
}

This variant is in my opinion better, especially if you also want to map from Term::False to Term::True.

Playground

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading