I was seeing if it would work with nested patterns and quasiquoted patterns and it didn't, so I had to change the rewrite function and use (vector? (syntax-e pat)) to check for a vector written like `#(,a:num ,b:num ,c:num).

like this:

 (define (rewrite pat)
     (cond [(identifier? pat) (let* ([pat-sym (syntax->datum pat)]
[pat-str (symbol->string pat- sym)])
                                (if (id:type? pat-str)
                                    (parse-pat-str pat-str stx)
                                    pat))]
[(syntax->list pat) (datum->syntax pat (map rewrite (syntax->list pat)))] [(vector? (syntax-e pat)) (datum->syntax pat (vector-map rewrite (syntax-e pat)))] [else (print pat) (newline) (error "I don't know what to do. given:" pat)]))

For the vector thing, I had to put a special clause in that did a vector-map instead of a map.

Is there any other stuff (like the #(1 2 3) notation for vectors) that I should be worried about, or is there another way to write the rewrite function to handle stuff like this that wouldn't require a cond case for every type of data that pat could be?

The whole thing is here:

#lang racket

(require rackunit)
(require (for-syntax
          (only-in lang/htdp-intermediate-lambda
                   string-contains?)
          racket/string
          racket/match
          racket/vector))

(begin-for-syntax
 (define (type-str->stx-type-pred type-str)
   (match type-str
     ["num" #'number?]
     ["str" #'string?]
     ["sym" #'symbol?]
     ["lst" #'list?]
     ["vec" #'vector?]
     ["bool" #'boolean?]
     ["proc" #'procedure?]
     [_ #f]))

 (define (split str) (string-split str ":"))

 (define (parse-pat-str pat-str stx)
   (match (split pat-str)
     [(list pat-name-str type-str)
      (with-syntax ([type-pred (type-str->stx-type-pred type-str)]
[pat-name (datum->syntax stx (string->symbol pat- name-str))])
        #'(? type-pred pat-name))]))

 (define (id:type? str)
   (and (string-contains? ":" str)
        (= 2 (length (split str)))
        (type-str->stx-type-pred (cadr (split str)))))
 )

(define-match-expander :pat
 (lambda (stx)
   (define (rewrite pat)
     (cond [(identifier? pat) (let* ([pat-sym (syntax->datum pat)]
[pat-str (symbol->string pat- sym)])
                                (if (id:type? pat-str)
                                    (parse-pat-str pat-str stx)
                                    pat))]
[(syntax->list pat) (datum->syntax pat (map rewrite (syntax->list pat)))] [(vector? (syntax-e pat)) (datum->syntax pat (vector-map rewrite (syntax-e pat)))] [else (print pat) (newline) (error "I don't know what to do. given:" pat)]))
   (syntax-case stx ()
     [(_ pat) (identifier? #'pat) (rewrite #'pat)]
     [(_ (pat ...))
      (with-syntax ([(p ...) (map rewrite (syntax->list #'(pat ...)))])
        (syntax/loc stx (p ...)))]
     [(_ pat) #'pat])))

(define-syntax (:match stx)
 (syntax-case stx ()
   [(:match val-expr [pat . more] ...)
(with-syntax ([(new-pat ...) (for/list ([pat-stx (in-list (syntax- >list #'(pat ...)))]) (datum->syntax pat-stx `(:pat , (syntax->datum pat-stx))))])
    #'(match val-expr [new-pat . more] ...))]))


(check-equal? (:match 1 [n:num n]) 1)
(check-equal? (:match 'x [n:num n] [_ 2]) 2)

(check-equal? (:match "string" [s:str s]) "string")
(check-equal? (:match 'x [s:str s] [_ 2]) 2)

(check-equal? (:match (list 1 2 3) [l:lst l]) (list 1 2 3))
(check-equal? (:match 'x [l:lst l] [_ 2]) 2)

(check-equal? (:match (vector 1 2 3) [v:vec v]) (vector 1 2 3))
(check-equal? (:match 'x [v:vec v] [_ 2]) 2)

(check-equal? (:match #t [b:bool b]) #t)
(check-equal? (:match #f [b:bool b]) #f)
(check-equal? (:match 'x [b:bool b] [_ 2]) 2)

(check-equal? (:match 'x [l l]) 'x)

(check-equal? (:match '(2 x "foo" (3 4)) [(list n s f l) (list n s f l)]) '(2 x "foo" (3 4)))
(check-equal? (:match '(42 x) [(list n:num s:sym) (list n s)]) '(42 x))

(check-equal? (:match '(1 2 #(1 2 3 (1 2 3 4)))
[(list a:num b:num (vector a:num b:num c:num (list a:num b:num c:num d:num)))
                       (list a b c d)])
              (list 1 2 3 4))

(check-equal? (:match '(1 2 #(1 2 3 (1 2 3 4)))
[`(,a:num ,b:num #(,a:num ,b:num ,c:num (,a:num ,b:num ,c:num ,d:num)))
                       (list a b c d)])
              (list 1 2 3 4))


On Dec 29, 2013, at 12:04 PM, Alexander D. Knauth wrote:

I'm not really sure why this works either, but try this:

(define-syntax (:match stx)
 (syntax-case stx ()
   [(:match val-expr [pat . more] ...)
(with-syntax ([(new-pat ...) (for/list ([pat-stx (in-list (syntax->list #'(pat ...)))]) (datum->syntax pat-stx `(:pat , (syntax->datum pat-stx))))])
    #'(match val-expr [new-pat . more] ...))]))

(check-equal? (:match '(42 x) [(list n:num s:sym) (list n s)])
              (match '(42 x) [(:pat (list n:num s:sym)) (list n s)]))

On Dec 29, 2013, at 8:54 AM, Jens Axel Søgaard wrote:

Hi Alexander,

I extended your example to allow other patterns than symbols inside :pat.

(match '(42 x)  [(:pat (list n:num s:sym))   (list n s)])
   (list 42 x)

This works fine. I now want to "hide" the :pat, that is I want to write:

   (:match '(42 x)  [(list n:num s:sym)  (list n s)])

Since the syntax of match is: (match val-expr clause ...) and each clause has the form [pat . more] we can rewrite pat to [(:pat pat) . more].

So I tried this:

 (define-syntax (:match stx)
   (syntax-case stx ()
     [(_ val-expr [pat . more] ...)
      #'(match val-expr [(:pat pat) . more] ...)]))

This doesn't work however. I am tempted to consider this a bug in match,
but I am not sure.

#lang racket
(require (for-syntax (only-in lang/htdp-intermediate-lambda string- contains?)
                    racket/string
                    racket/match)
        rackunit)

(begin-for-syntax
 (define (type-str->stx-type-pred type-str)
   (match type-str
     ["num" #'number?]
     ["str" #'string?]
     ["sym" #'symbol?]
     ["lst" #'list?]
     [_ #f]))

 (define (split str) (string-split str ":"))

 (define (parse-pat-str pat-str stx)
   (match (split pat-str)
     [(list pat-name-str type-str)
      (with-syntax ([type-pred (type-str->stx-type-pred type-str)]
                    [pat-name (datum->syntax stx (string->symbol
pat-name-str))])
        #'(? type-pred pat-name))]))

 (define (id:type? str)
   (and (string-contains? ":" str)
        (type-str->stx-type-pred (cadr (split str))))))

(define-match-expander :pat
 (lambda (stx)
   (define (rewrite pat)
     (let* ([pat-sym (syntax->datum pat)]
            [pat-str (symbol->string pat-sym)])
       (if (id:type? pat-str)
           (parse-pat-str pat-str stx)
           pat)))
   (syntax-case stx ()
     [(_ pat) (identifier? #'pat) (rewrite #'pat)]
     [(_ (pat ...))
(with-syntax ([(p ...) (map rewrite (syntax->list #'(pat ...)))])
        (syntax/loc stx (p ...)))]
     [(_ pat) #'pat])))

(define-syntax (:match stx)
 (syntax-case stx ()
   [(_ val-expr [pat . more] ...)
    #'(match val-expr [(:pat pat) . more] ...)]))


(check-equal? (match 1 [(:pat n:num) n]) 1)
(check-equal? (match 'x [(:pat n:num) n] [_ 2]) 2)

(check-equal? (match "string" [(:pat s:str) s]) "string")
(check-equal? (match 'x [(:pat s:str) s] [_ 2]) 2)

(check-equal? (match (list 1 2 3) [(:pat l:lst) l]) (list 1 2 3))
(check-equal? (match 'x [(:pat l:lst) l] [_ 2]) 2)

(check-equal? (match 'x [(:pat l) l]) 'x)

(check-equal? (match '(2 x "foo" (3 4)) [(:pat (list n s f l)) (list n
s f l)]) '(2 x "foo" (3 4)))
(check-equal? (match '(42 x) [(:pat (list n:num s:sym)) (list n s)]) '(42 x))


(match '(42 x) [(:pat (list n:num s:sym)) (list n s)])
; (:match '(42 x) [(list n:num s:sym) (list n s)])



2013/12/28 Alexander D.Knauth <alexan...@knauth.org>:
I just wrote a match-expander that does something like that:

(check-equal? (match 1 [(my-pat n:num) n]) 1)
(check-equal? (match 'x [(my-pat n:num) n] [_ 2]) 2)

like this:

#lang racket

(require rackunit)
(require (for-syntax
         (only-in lang/htdp-intermediate-lambda
                  string-contains?)
         racket/string
         racket/match))

(define-match-expander my-pat
 (lambda (stx)
   (syntax-case stx ()
     [(my-pat pat)
      (let* ([pat-sym (syntax->datum #'pat)]
             [pat-str (symbol->string pat-sym)])
        (cond [(not (string-contains? ":" pat-str))
               #'pat]
              [else
               (parse-pat-str pat-str stx)]))])))

(define-for-syntax (parse-pat-str pat-str stx)
 (let ([split-pat (string-split pat-str ":")])
   (match split-pat
     [(list pat-name-str type-str)
      (with-syntax ([type-pred (type-str->stx-type-pred type-str)]
                    [pat-name (datum->syntax stx (string->symbol
pat-name-str))])
        #'(? type-pred pat-name))])))

(define-for-syntax (type-str->stx-type-pred type-str)
 (match type-str
   ["num" #'number?]
   ["str" #'string?]
   ["lst" #'list?]))

(check-equal? (match 1 [(my-pat n:num) n]) 1)
(check-equal? (match 'x [(my-pat n:num) n] [_ 2]) 2)

(check-equal? (match "string" [(my-pat s:str) s]) "string")
(check-equal? (match 'x [(my-pat s:str) s] [_ 2]) 2)

(check-equal? (match (list 1 2 3) [(my-pat l:lst) l]) (list 1 2 3))
(check-equal? (match 'x [(my-pat l:lst) l] [_ 2]) 2)



On Dec 26, 2013, at 2:45 PM, Jens Axel Søgaard wrote:

The match pattern (? number? n) matches  number and
binds it to n.

(match 1 [(? number? n) n])

 1

I'd like to write  (match 1 [n:num n]) instead.

Since there is no define-identifier-match-expander I have
tried to make (match 1 [(n:num) n]) work. I need a hint.

Here is a non-working attempt:

(define-match-expander n:num
(λ(stx)
  (syntax-case stx ()
    [(id)
     (with-syntax ([n (syntax/loc #'id n)])
       #'(? number? n))])))


(check-equal? (match 1 [(n:num) n]) 1)
(check-equal? (match 'x [(n:num) n] [_ 2]) 2)

/Jens Axel






--
Jens Axel Søgaard

____________________
Racket Users list:
http://lists.racket-lang.org/users





--
--
Jens Axel Søgaard

____________________
 Racket Users list:
 http://lists.racket-lang.org/users

____________________
  Racket Users list:
  http://lists.racket-lang.org/users

Reply via email to