how to recursively and lazily simplify a lisp-like expression?

  Kiến thức lập trình

I am trying to process a lisp-like Sexp by recursively applying an optional simplifier to each node of the expression, and saving the result to an internal AST structure. The simplifier may stop processing sub-expressions (aka arguments) when they become unnecessary (lazyness). For example, one does not need to process C and D in the logical and expression (and A B false C D) because its simplification is false anyway.

I could not find a way to implement lazyness: please help. Furthermore, the strict implementation I wrote raised an expected IntoIter<Index>, found type parameter T error in the body of a function declared with where T: Iterator<Item=Index>. Yet, the definition of IntoInter<Index> is Iterator<Item=Index>. So, the types should match, shouldn’t they? I guess the explanation is that Iterator is a trait and IntoIter a type, but how do I resolve the problem?

Hopefully, the code below is detailed enough. Tags is an enum with the list of recognized node tags. Strings are mapped to Tags using strum_macros.

    // adds a symbolic expression to the target AST
    pub fn add_sexp<T>(
        &mut self, // the target AST structure
        sexp: Sexp,
        simplifier: Option<fn(Tags, T, &mut Asg) -> Either<Node, Index>>,
    ) -> Index where T: Iterator<Item=Index> {
        match sexp {
            Sexp::String(symb) => // a leaf of the tree
                return self.add_node(Node::String(symb)),
            Sexp::List(args) => {  // recursively process a node
                match &args[0] {
                    Sexp::List(_) => panic!("a tag cannot be a list"),
                    Sexp::String(t) => {  // use strum_macros
                        let tag = match Tags::from_str(t.as_str()) {
                            Ok(tag_) => tag_,
                            _ => panic!("Unknown tag")
                        };
                        // it should not be necessary to process each sub-expr in advance
                        // I should construct an Iterator<Item=Index> instead of a Vec
                        let args_ : Vec<Index> = args[1..].iter()
                            .map(|a|
                                self.add_sexp(a.clone(), simplifier)).collect();
                        return self.add_internal(tag,
                            args_.into_iter(),
                            simplifier)  // this is where the error occurs
                        }
                    Sexp::Empty => panic!("empty tag")
                }
            }
            Sexp::Empty => {
                panic!("empty input")
            }
        }
    }

    // adds an internal node to the target AST after simplifying it
    pub fn add_internal<T>(
        &mut self,
        tag: Tags,
        generator: T,
        simplifier: Option<fn(Tags, T, &mut Asg) -> Either<Node, Index>>
    ) -> Index where T: Iterator<Item=Index> {
        match simplifier {
            None => return self.add_node(Node::Internal{tag: tag, args: generator.collect()}),
            Some(s) => {
                match s(tag, generator, self) {
                    Left(n) => return self.add_node(n),
                    Right(i) => return i
                }}
        };
    }

The error is

error[E0308]: mismatched types
   --> src/asg/mod.rs:118:29
    |
97  | ...sexp<T>(
    |         - found this type parameter
...
116 | ...         return self.add_internal(tag,
    |                         ------------ arguments to this method are incorrect
117 | ...             args_.into_iter(),
118 | ...             simplifier)
    |                 ^^^^^^^^^^ expected `IntoIter<Index>`, found type parameter `T`
    |
    = note: expected enum `Option<for<'a> fn(Tags, std::vec::IntoIter<asg::Index>, &'a mut Asg) -> Either<_, _>>`
               found enum `Option<for<'a> fn(Tags, T, &'a mut Asg) -> Either<_, _>>`
note: method defined here
   --> src/asg/mod.rs:81:12
    |
81  | ...ub fn add_internal<T>(
    |          ^^^^^^^^^^^^
...
85  | ...   simplifier: Option<fn(Tags, T, &mut Asg) -> Either<Node, Index>>
    |       ----------------------------------------------------------------

But I’m really looking for a lazy solution.

LEAVE A COMMENT