1.11 S-Expression Matching🔗ℹ

Since the equal? function works on any kind of value, it can compare two S-expressions to determine whether they are the same:

> (equal? `{+ 1 2} `{+ 1 2})

- Boolean

#t

> (equal? `{+ 1 2} `{+ 1 4})

- Boolean

#f

Suppose that you don’t just want to recognize `{+ 1 2}, but you want to recognize any list-like S-expression that has three elements where the first element is '+-like and the other two elements are number-like. That recognition problem is tedious to implement, due to the many required many checks and coercions.

> (define (is-plus-numbers? se)
    (and (s-exp-list? se)
         (let ([l (s-exp->list se)])
           (and (= 3 (length l))
                (let ([a (first l)])
                  (and (s-exp-symbol? a)
                       (eq? '+ (s-exp->symbol a))))
                (s-exp-number? (second l))
                (s-exp-number? (third l))))))
> (is-plus-numbers? `{+ 1 2})

- Boolean

#t

> (is-plus-numbers? `1)

- Boolean

#f

> (is-plus-numbers? `{+ 3 y})

- Boolean

#f

> (is-plus-numbers? `{{+} 1 2})

- Boolean

#f

The s-exp-match? function simplifies recognition tasks for S-expressions. It’s like equal? on S-expressions, but the first S-expression can have special symbols that match different classes of values, instead of matching themselves literally. The special symbols include NUMBER, which matchs any number, so is-plus-numbers? is more simply implemented like this:

> (define (is-plus-numbers? se)
    (s-exp-match? `{+ NUMBER NUMBER} se))
> (is-plus-numbers? `{+ 1 2})

- Boolean

#t

> (is-plus-numbers? `{+ 3 y})

- Boolean

#f

Other special symbols include SYMBOL, which matches any symbol, and ANY, which matches anything.

> (define (single-argument-lambda? se)
    (s-exp-match? `{lambda {SYMBOL} ANY} se))
> (single-argument-lambda? `{lambda {x} {+ x 1}})

- Boolean

#t

> (single-argument-lambda? `{lambada 0})

- Boolean

#f

The symbol ... is even more special. It causes the preceeding S-expression to match zero or more times to cover multiple elements in an enclosing list. For example, `{SYMBOL ...} would match a list-like S-expression that has any number of symbol-like elements.

> (define (any-argument-lambda? se)
    (s-exp-match? `{lambda {SYMBOL ...} ANY} se))
> (any-argument-lambda? `{lambda {x} {+ x 1}})

- Boolean

#t

> (any-argument-lambda? `{lambda {x y z} {+ x 1}})

- Boolean

#t

> (any-argument-lambda? `{lambda {} {+ x 1}})

- Boolean

#t

> (any-argument-lambda? `{lambada 0})

- Boolean

#f