Custom pattern-matching facility for Chez Scheme

309 views Asked by At

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)))
1

There are 1 answers

1
AudioBubble On BEST ANSWER

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.

  • First of all your macro refers to sexpr which has no meaning in the macro, and because Scheme macros are hygienic it will definitely not refer to the sexpr which is the argument to classify-sexpr.
  • Secondly you don't need a macro at all here. I suspect that you may be thinking that because you are trying to write a macro you must use macros in its construction: that's not necessarily true and often a bad idea.
  • Thirdly the syntax of your cond is botched beyond repair: I can't work out what it's trying to do.
  • Finally the list classification will never be needed: if you want to classify (1 2 3 (x)) as (number number number (symbol)) then you'll simply never reach a case where you have a list which you want to classify since you must walk into it to classify its elements.

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))))