macrospattern-matchingschemes-expressiondefine-syntax

Custom pattern-matching facility for Chez Scheme


I am trying to make my own pattern-matching system in Scheme. To begin I am making a parser for s-expressions that divides them into tokens like this:

'(1 2 b (3 4)) => '(number number symbol (number number))

It should be noted that I have not used define-syntax before in Scheme so that may be where I am messing up. Chez Scheme throws me this error: Exception: invalid syntax classify at line 21, char 4 of pmatch.scm. Note that the line numbers won't correspond exactly to the snippet here. Does anyone know what I am doing wrong?

(define-syntax classify
  (syntax-rules ()
    ((_ checker replacement)
     ((checker (car sexpr)) (cons replacement (classify-sexpr (cdr sexpr)))))))

(define (classify-sexpr sexpr)
    (cond
        ((null? sexpr) sexpr)
        (classify list? (classify-sexpr (car sexpr)))
        (classify number? 'number)
        (classify symbol? 'symbol)
        (else
          (cons 'symbol (classify-sexpr (cdr sexpr))))))

(display (classify-sexpr '(1 (b 3) (4 5) 6)))

Solution

  • Your code is hugely confused. In fact it's so confused I'm not sure what you're trying to do completely: I've based my answer on what you say the classifier should produce at the start of your question.

    Instead just write the obvious functions do do what you want:

    (define classification-rules
      ;; an alist of predicate / replacement which drives classigy
      `((,number? number)
        (,symbol? symbol)))
        
    (define (classify thing)
      ;; classify thing using classification-rules
      (let loop ([tail classification-rules])
        (cond [(null? tail)
               'something]
              [((first (first tail)) thing)
               (second (first tail))]
              [else
               (loop (rest tail))])))
    
    (define (classify-sexpr sexpr)
      ;; classify a sexpr using classify.
      (cond
        [(null? sexpr) '()]
        [(cons? sexpr) (cons (classify-sexpr (car sexpr))
                             (classify-sexpr (cdr sexpr)))]
        [else (classify sexpr)]))
    

    And now

    > (classify-sexpr '(1 2 3 (x 2) y))
    '(number number number (symbol number) symbol)
    

    It may be that what you really want is something which classifies (1 2 (x 2)) as (list number number (list symbol number)) say. You can do this fairly easily:

    (define atomic-classification-rules
      ;; an alist of predicate / replacements for non-conses
      `((,number? number)
        (,symbol? symbol)))
        
    (define (classify-sexpr sexpr)
      (cond
        [(null? sexpr) '()]
        [(list? sexpr)
         `(list ,@(map classify-sexpr sexpr))]
        [(cons? sexpr)
         `(cons ,(classify-sexpr (car sexpr))
                ,(classify-sexpr (cdr sexpr)))]
        [else
         (let caloop ([rtail atomic-classification-rules])
           (cond [(null? rtail)
                  'unknown]
                 [((first (first rtail)) sexpr)
                  (second (first rtail))]
                 [else
                  (caloop (rest rtail))]))]))
    

    And now

    > (classify-sexpr '(1 2 3 (x 2) y))
    '(list number number number (list symbol number) symbol)
    > (classify-sexpr '(1 2 3 (x 2) . y))
    '(cons number (cons number (cons number (cons (list symbol number) symbol))))