racket/collects/tests/match/examples.rkt
Sam Tobin-Hochstadt 8055d9f5f8 Allow multiple right hand sides in match/values.
Closes PR 12613.
2012-03-01 15:05:51 -05:00

709 lines
16 KiB
Racket

#lang scheme/base
(require scheme/match
scheme/mpair
scheme/control scheme/foreign
(for-syntax scheme/base)
(prefix-in m: mzlib/match)
(only-in srfi/13 string-contains)
rackunit)
(define-syntax (comp stx)
(syntax-case stx ()
[(mytest tst exp)
#`(test-case (format "test: ~a" (syntax->datum (quote-syntax tst)))
#,(syntax/loc stx (check-equal? tst exp)))]))
(define-struct X (a b c))
(define-match-expander X:
(lambda (stx)
(syntax-case stx ()
[(_ . args) #'(struct X args)])))
(define (f x y)
(match*
(x y)
[((box a) (box b)) (+ a b)]
[((vector x y z) (vector _)) (* x y z)]
[((list a b c) (list d)) (+ a b c d)]
[((cons a b) (cons c _)) (+ a b c)]))
(define (g x)
(match x
[1 'one]
[(and x (? number?)) (list x 'num)]
[(? boolean?) 'bool]
[_ 'neither]))
(define (split l)
(match l
[(list (list a b) ...) (list a b)]
[_ 'wrong]))
(define (split2 l)
(match l
[(list (list a b) ..2 rest) (list a b rest)]
[_ 'wrong]))
(define-struct empt ())
(provide new-tests)
(define new-tests
(test-suite
"new tests for match"
(comp
1
(match (list 1 2 3)
[(list x ...) (=> unmatch)
(if (= (car x) 1)
(begin (+ 100 (unmatch))
(error 'bad))
0)]
[_ 1]))
(comp
'(1 2 3)
(match (vector 1 2 3)
[(vector (? number? x) ...) x]
[_ 2]))
(comp
2
(match (vector 'a 1 2 3)
[(vector (? number? x) ...) x]
[_ 2]))
(comp
3
(match (list 'a 1 2 3)
[(vector (? number? x) ...) x]
[_ 3]))
(comp -1
(match (vector 1 2 3)
[(or (list x) x) -1]
[(list a b c) 0]
[(vector a) 1]
[(vector a b) 2]
[(vector a b c) 3]
[(box _) 4]))
(comp 12
(match (list 12 12)
[(list x x) x]
[_ 13]))
(comp 13
(match (list 1 0)
[(list x x) x]
[_ 13]))
(comp
6
(let ()
(match (make-X 1 2 3)
[(struct X (a b c)) (+ a b c)]
[(box a) a]
[(cons x y) (+ x y)]
[_ 0])))
(comp
6
(let ()
(match (make-X 1 2 3)
[(X a b c) (+ a b c)]
[(box a) a]
[(cons x y) (+ x y)]
[_ 0])))
(comp
6
(match (make-X 1 2 3)
[(X: a b c) (+ a b c)]))
(comp
'(6 3 100 6)
(list
(f (cons 1 2) (cons 3 4))
(f (box 1) (box 2))
(f (list 10 20 30) (list 40))
(f (vector 1 2 3) (vector 4))))
(comp '(one (2 num) bool neither)
(list
(g 1)
(g 2)
(g #f)
(g "foo")))
(comp
(split (list (list 1 2) (list 'a 'b) (list 'x 'y)))
'((1 a x) (2 b y)))
(comp
(split2 (list (list 1 2) (list 'a 'b) (list 'x 'y)))
'((1 a) (2 b) (x y)))
(comp
'yes
(match (list (box 2) 2)
[(list (or (box x) (list x)) x) 'yes]
[_ 'no]))
(comp
'no
(parameterize ([match-equality-test eq?])
(match (list (cons 1 1) (cons 1 1))
[(list x x) 'yes]
[_ 'no])))
(comp
'no
(match (list (box 2) 3)
[(list (or (box x) (list x)) x) 'yes]
[_ 'no]))
(comp
2
(match (list 'one 'three)
[(list 'one 'two) 1]
[(list 'one 'three) 2]
[(list 'two 'three) 3]))
(comp
2
(match (list 'one 'three)
[(cons 'one (cons 'two '())) 1]
[(cons 'one (cons 'three '())) 2]
[(cons 'two (cons 'three '())) 3]))
(comp 'yes
(match '(1 x 2 y 3 z)
[(list-no-order 1 2 3 'x 'y 'z) 'yes]
[_ 'no]))
;; NOT WORKING YET
(comp '(x y z)
(match '(1 x 2 y 3 z)
[(list-no-order 1 2 3 r1 r2 r3) (list r1 r2 r3)]
[_ 'no]))
(comp '(x y z)
(match '(1 x 2 y 3 z)
[(list-no-order 1 2 3 rest ...) rest]
[_ 'no]))
(comp
'yes
(match '(a (c d))
[(list-no-order 'a
(? pair?
(list-no-order 'c 'd)))
'yes]
[_ 'no]))
(comp
'((1 2) (a b 1 2))
(let ()
(define-syntax-rule (match-lambda . cl)
(lambda (e) (match e . cl)))
(define (make-nil)
'())
(define nil? null?)
(define make-::
(match-lambda
((list-no-order (list '|1| a) (list '|2| d))
(cons a d))))
(define ::? pair?)
(define (::-content p)
(list (list '|1| (car p))
(list '|2| (cdr p))))
(define my-append
(match-lambda
((list-no-order (list '|1| (? nil?))
(list '|2| l))
l)
((list-no-order (list '|1| (? ::?
(app ::-content (list-no-order (list
'|1| h) (list '|2| t)))))
(list '|2| l))
(make-:: (list (list '|1| h)
(list '|2| (my-append (list (list '|1| t) (list '|2|
l)))))))))
(list
(my-append (list (list '|1| '())
(list '|2| '(1 2))))
(my-append (list (list '|1| '(a b))
(list '|2| '(1 2)))))))
(comp
'yes
(match
(make-immutable-hasheq '((|1| . (a b))))
[(hash-table ('|1| (app (lambda (p)
(make-immutable-hasheq
(list (cons '|1| (car p))
(cons '|2| (cdr p)))))
(hash-table ('|1| _) ('|2| _))))) 'yes]
[_ 'no]))
;; examples from docs
(comp 'yes
(match '(1 2 3)
[(list (not 4) ...) 'yes]
[_ 'no]))
(comp 'no
(match '(1 4 3)
[(list (not 4) ...) 'yes]
[_ 'no]))
(comp 1
(match '(1 2)
[(or (list a 1) (list a 2)) a]
[_ 'bad]))
(comp '(2 3)
(match '(1 (2 3) 4)
[(list _ (and a (list _ ...)) _) a]
[_ 'bad]))
(comp
'yes
(match "apple"
[(regexp #rx"p+(.)" (list _ "l")) 'yes]
[_ 'no]))
(comp
'no
(match "append"
[(regexp #rx"p+(.)" (list _ "l")) 'yes]
[_ 'no]))
(comp
'yes
(match "apple"
[(regexp #rx"p+" ) 'yes]
[_ 'no]))
(comp
'no
(match "banana"
[(regexp #rx"p+") 'yes]
[_ 'no]))
(comp
'(0 1)
(let ()
(define-struct tree (val left right))
(match (make-tree 0 (make-tree 1 #f #f) #f)
[(struct tree (a (struct tree (b _ _)) _)) (list a b)]
[_ 'no])))
(comp 1
(match #&1
[(box a) a]
[_ 'no]))
(comp '(2 1)
(match #hasheq(("a" . 1) ("b" . 2))
[(hash-table ("b" b) ("a" a)) (list b a)]
[_ 'no]))
(comp #t
(andmap string?
(match #hasheq(("b" . 2) ("a" . 1))
[(hash-table (key val) ...) key]
[_ 'no])))
(comp
(match #(1 (2) (2) (2) 5)
[(vector 1 (list a) ..3 5) a]
[_ 'no])
'(2 2 2))
(comp '(1 3 4 5)
(match '(1 2 3 4 5 6)
[(list-no-order 6 2 y ...) y]
[_ 'no]))
(comp 1
(match '(1 2 3)
[(list-no-order 3 2 x) x]))
(comp '((1 2 3) 4)
(match '(1 2 3 . 4)
[(list-rest a ... d) (list a d)]))
(comp 4
(match '(1 2 3 . 4)
[(list-rest a b c d) d]))
;; different behavior from the way match used to be
(comp '(2 3 4)
(match '(1 2 3 4 5)
[(list 1 a ..3 5) a]
[_ 'else]))
(comp '((1 2 3 4) ())
(match (list 1 2 3 4 5)
[(list x ... y ... 5) (list x y)]
[_ 'no]))
(comp '((1 3 2) (4))
(match (list 1 3 2 3 4 5)
[(list x ... 3 y ... 5) (list x y)]
[_ 'no]))
(comp '(3 2 1)
(match '(1 2 3)
[(list a b c) (list c b a)]))
(comp '(2 3)
(match '(1 2 3)
[(list 1 a ...) a]))
(comp 'else
(match '(1 2 3)
[(list 1 a ..3) a]
[_ 'else]))
(comp '(2 3 4)
(match '(1 2 3 4)
[(list 1 a ..3) a]
[_ 'else]))
(comp
'(2 2 2)
(match '(1 (2) (2) (2) 5)
[(list 1 (list a) ..3 5) a]
[_ 'else]))
(comp
#t
(match "yes"
["yes" #t]
["no" #f]))
(comp 3
(match '(1 2 3)
[(list _ _ a) a]))
(comp '(3 2 1)
(match '(1 2 3)
[(list a b a) (list a b)]
[(list a b c) (list c b a)]))
(comp '(2 '(x y z) 1)
(match '(1 '(x y z) 2)
[(list a b a) (list a b)]
[(list a b c) (list c b a)]))
(comp '(1 '(x y z))
(match '(1 '(x y z) 1)
[(list a b a) (list a b)]
[(list a b c) (list c b a)]))
(comp '(2 3)
(match '(1 2 3)
[`(1 ,a ,(? odd? b)) (list a b)]))
(comp '(2 1 (1 2 3 4))
(match-let ([(list a b) '(1 2)]
[(vector x ...) #(1 2 3 4)])
(list b a x)))
(comp '(1 2 3 4)
(match-let* ([(list a b) '(#(1 2 3 4) 2)]
[(vector x ...) a])
x))
(comp 2
(let ()
(match-define (list a b) '(1 2))
b))
(comp 'yes
(match '(number_1 . number_2)
[`(variable-except ,@(list vars ...))
'no]
[(? list?)
'no]
[_ 'yes]))
(comp "yes"
(match
'((555))
((list-no-order (and (list 555)
(list-no-order 555)))
"yes")
(_ "no"))) ;; prints "no"
(comp "yes"
(match
'((555))
((list-no-order (and (list-no-order 555)
(list 555)))
"yes")
(_ "no"))) ;; prints "yes"
(comp "yes"
(match
'((555))
((list (and (list 555)
(list-no-order 555)))
"yes")
(_ "no"))) ;; prints "yes"
(comp '("a") (match "a" ((regexp #rx"a" x) x)))
(comp '(#"a")
(match #"a"
((regexp #rx"a" x) x)
[_ 'no]))
(comp 'yes (match #"a" (#"a" 'yes)))
(comp 'yes (with-handlers ([exn:fail:syntax? (lambda _ 'yes)]) (expand #'(match-lambda ((a ?) #f))) 'no))
(comp 'yes (with-handlers ([exn:fail:syntax? (lambda _ 'yes)]) (expand #'(match-lambda ((?) #f))) 'no))
(comp
'yes
(let ()
(m:define-match-expander exp1
#:plt-match
(lambda (stx)
(syntax-case stx ()
((_match (x y))
#'(list (list x y))))))
(m:define-match-expander exp2
#:plt-match
(lambda (stx)
(syntax-case stx ()
((_match x y)
#'(exp1 (x y))))))
(define (test tp)
(match tp ((exp2 x y) x)))
'yes))
(comp '(a b c)
(match '(a b c)
[(list-rest foo) foo]))
(comp 2
(let ()
(define (foo x) (match x [1 (+ x x)]))
(foo 1)))
(comp 'yes
(match (make-empt)
[(struct empt ()) 'yes]
[_ 'no]))
(comp 'yes
(m:match (make-empt)
[($ empt) 'yes]
[_ 'no]))
(comp 3
(match (mcons 1 2)
[(mcons a b) (+ a b)]
[_ 'no]))
(comp 3
(match (mlist 1 2)
[(mlist a b) (+ a b)]
[_ 'no]))
(comp 3
(match (mlist 1 2)
[(mlist a ...) (apply + a)]
[_ 'no]))
(comp 1
(match (box 'x) ('#&x 1) (else #f)))
(comp 2
(match (vector 1 2) ('#(1 2) 2) (else #f)))
(comp 'yes
(with-handlers ([exn:fail? (lambda _ 'yes)]
[values (lambda _ 'no)])
(match 1)
'no))
(comp 'yes
(with-handlers ([exn:fail:syntax? (lambda _ 'yes)]
[values (lambda _ 'no)])
(expand #'(let ()
(define-struct foo (bar))
(define the-bar (match (make-foo 42)
[(struct foo bar) ;; note the bad syntax
bar]))
0))))
;; raises error
(comp 'yes (with-handlers ([exn:fail:syntax? (lambda _ 'yes)])
(expand (quote-syntax (match '(1 x 2 y 3 z)
[(list-no-order 1 2 3 rest ... e) rest]
[_ 'no])))
'no))
(comp '((2 4) (2 1))
(match '(3 2 4 3 2 1)
[(list x y ... x z ...)
(list y z)]))
(comp '(1 2)
(match-let ([(vector a b) (vector 1 2)])
(list a b)))
(comp '(4 5)
(let-values ([(x y)
(match 1
[(or (and x 2) (and x 3) (and x 4)) 3]
[_ (values 4 5)])])
(list x y)))
(comp 'bad
(match #(1)
[(vector a b) a]
[else 'bad]))
(comp '(1 2)
(call-with-values
(lambda ()
(match 'foo [_ (=> skip) (skip)] [_ (values 1 2)]))
list))
(comp 0
(let ([z (make-parameter 0)])
(match 1
[(? number?) (=> f) (parameterize ([z 1]) (f))]
[(? number?) (z)])))
;; make sure the prompts don't interfere
(comp 12
(%
(let ([z (make-parameter 0)])
(match 1
[(? number?) (=> f) (parameterize ([z 1]) (fcontrol 5))]
[(? number?) (z)]))
(lambda _ 12)))
(comp 4
(match 3
[(or) 1]
[_ 4]))
(comp '((1 2) 3)
(match `(begin 1 2 3)
[`(begin ,es ... ,en)
(list es en)]))
(comp '(a b c)
(let ()
(define-struct foo (a b c) #:prefab)
(match (make-foo 'a 'b 'c)
[`#s(foo ,x ,y ,z)
(list x y z)])))
(comp '(a b c)
(let ()
(define-struct foo (a b c) #:prefab)
(define-struct (bar foo) (d) #:prefab)
(match (make-bar 'a 'b 'c 1)
[`#s((bar foo 3) ,x ,y ,z ,w)
(list x y z)])
))
(comp "Gotcha!"
(let ()
(define-cstruct _pose
([x _double*]
[y _double*]
[a _double*]))
(match (make-pose 1 2 3)
[(struct pose (x y a)) "Gotcha!"]
[else "Epic fail!"])))
(comp #f
(match (list 'a 'b 'c)
[(or (list a b)
(and (app (lambda _ #f) b)
(or (and (app (lambda _ #f) a)
(list))
(list a))))
#t]
[_ #f]))
(comp '(2 7)
(let ()
(define-match-expander foo
(syntax-rules () [(_) 1])
(syntax-id-rules (set!)
[(set! _ v) v]
[(_) 2]))
(list (foo)
(set! foo 7))))
(comp 0
(let ()
(define-match-expander foo
(syntax-id-rules () [_ 10]))
(match 10
[(foo) 0]
[_ 1])))
(comp '(1 2 4)
(call-with-values
(λ () (match-let-values ([(x y) (values 1 2)] [(3 w) (values 3 4)])
(values x y w)))
list))
(comp '(1 3 4)
(call-with-values
(λ () (match-let*-values ([(x y) (values 1 2)] [(y w) (values 3 4)])
(values x y w)))
list))
(comp '(1 2 3)
(match/values (values 1 2 3)
[(x y z) (list x y z)]))
(comp '(1 2)
(let () (match-define-values (x y 3) (values 1 2 3))
(list x y)))
(comp '(1 2 3)
(match-let ([(list x y) (list 1 2)] [(list y z) '(2 3)])
(list x y z)))
(comp 'yes (match/values (values 1 2) [(x y) 0 'yes] [(_ _) 'no]))
(comp 'yes
(with-handlers ([exn:fail? (lambda _ 'yes)]
[values (lambda _ 'no)])
(match-let ([(list x y) (list 1 22)] [(list y z) '(2 3)])
(list x y z))))
))