Adding Gauche's `@' pattern for named record field matching.

Also adding the `struct' and `object' aliases for `$' and `@' respectively.
This commit is contained in:
Alex Shinn 2014-11-24 19:49:59 +09:00
parent e0afb1df85
commit f4f3949b4e
2 changed files with 62 additions and 3 deletions

View file

@ -164,6 +164,21 @@
;;> (($ employee n t) (list t n)))) ;;> (($ employee n t) (list t n))))
;;> } ;;> }
;;> For records with more fields it can be helpful to match them by
;;> name rather than position. For this you can use the \scheme{@}
;;> operator, originally a Gauche extension:
;;> \example{
;;> (let ()
;;> (define-record-type employee
;;> (make-employee name title)
;;> employee?
;;> (name get-name)
;;> (title get-title))
;;> (match (make-employee "Bob" "Doctor")
;;> ((@ employee (title t) (name n)) (list t n))))
;;> }
;;> The \scheme{set!} and \scheme{get!} operators are used to bind an ;;> The \scheme{set!} and \scheme{get!} operators are used to bind an
;;> identifier to the setter and getter of a field, respectively. The ;;> identifier to the setter and getter of a field, respectively. The
;;> setter is a procedure of one argument, which mutates the field to ;;> setter is a procedure of one argument, which mutates the field to
@ -212,6 +227,7 @@
;; performance can be found at ;; performance can be found at
;; http://synthcode.com/scheme/match-cond-expand.scm ;; http://synthcode.com/scheme/match-cond-expand.scm
;; ;;
;; 2014/11/24 - adding Gauche's `@' pattern for named record field matching
;; 2012/12/26 - wrapping match-let&co body in lexical closure ;; 2012/12/26 - wrapping match-let&co body in lexical closure
;; 2012/11/28 - fixing typo s/vetor/vector in largely unused set! code ;; 2012/11/28 - fixing typo s/vetor/vector in largely unused set! code
;; 2012/05/23 - fixing combinatorial explosion of code in certain or patterns ;; 2012/05/23 - fixing combinatorial explosion of code in certain or patterns
@ -333,7 +349,7 @@
;; pattern so far. ;; pattern so far.
(define-syntax match-two (define-syntax match-two
(syntax-rules (_ ___ ..1 *** quote quasiquote ? $ = and or not set! get!) (syntax-rules (_ ___ ..1 *** quote quasiquote ? $ struct @ object = and or not set! get!)
((match-two v () g+s (sk ...) fk i) ((match-two v () g+s (sk ...) fk i)
(if (null? v) (sk ... i) fk)) (if (null? v) (sk ... i) fk))
((match-two v (quote p) g+s (sk ...) fk i) ((match-two v (quote p) g+s (sk ...) fk i)
@ -377,6 +393,18 @@
(if (is-a? v rec) (if (is-a? v rec)
(match-record-refs v rec 0 (p ...) g+s sk fk i) (match-record-refs v rec 0 (p ...) g+s sk fk i)
fk)) fk))
((match-two v (struct rec p ...) g+s sk fk i)
(if (is-a? v rec)
(match-record-refs v rec 0 (p ...) g+s sk fk i)
fk))
((match-two v (@ rec p ...) g+s sk fk i)
(if (is-a? v rec)
(match-record-named-refs v rec (p ...) g+s sk fk i)
fk))
((match-two v (object rec p ...) g+s sk fk i)
(if (is-a? v rec)
(match-record-named-refs v rec (p ...) g+s sk fk i)
fk))
((match-two v (p . q) g+s sk fk i) ((match-two v (p . q) g+s sk fk i)
(if (pair? v) (if (pair? v)
(let ((w (car v)) (x (cdr v))) (let ((w (car v)) (x (cdr v)))
@ -688,6 +716,15 @@
((_ v rec n () g+s (sk ...) fk i) ((_ v rec n () g+s (sk ...) fk i)
(sk ... i)))) (sk ... i))))
(define-syntax match-record-named-refs
(syntax-rules ()
((_ v rec ((f p) . q) g+s sk fk i)
(let ((w (slot-ref rec v 'f)))
(match-one w p ((slot-ref rec v 'f) (slot-set! rec v 'f))
(match-record-named-refs v rec q g+s sk fk) fk i)))
((_ v rec () g+s (sk ...) fk i)
(sk ... i))))
;; Extract all identifiers in a pattern. A little more complicated ;; Extract all identifiers in a pattern. A little more complicated
;; than just looking for symbols, we need to ignore special keywords ;; than just looking for symbols, we need to ignore special keywords
;; and non-pattern forms (such as the predicate expression in ? ;; and non-pattern forms (such as the predicate expression in ?
@ -701,11 +738,17 @@
;; (match-extract-vars pattern continuation (ids ...) (new-vars ...)) ;; (match-extract-vars pattern continuation (ids ...) (new-vars ...))
(define-syntax match-extract-vars (define-syntax match-extract-vars
(syntax-rules (_ ___ ..1 *** ? $ = quote quasiquote and or not get! set!) (syntax-rules (_ ___ ..1 *** ? $ struct @ object = quote quasiquote and or not get! set!)
((match-extract-vars (? pred . p) . x) ((match-extract-vars (? pred . p) . x)
(match-extract-vars p . x)) (match-extract-vars p . x))
((match-extract-vars ($ rec . p) . x) ((match-extract-vars ($ rec . p) . x)
(match-extract-vars p . x)) (match-extract-vars p . x))
((match-extract-vars (struct rec . p) . x)
(match-extract-vars p . x))
((match-extract-vars (@ rec (f p) ...) . x)
(match-extract-vars (p ...) . x))
((match-extract-vars (object rec (f p) ...) . x)
(match-extract-vars (p ...) . x))
((match-extract-vars (= proc p) . x) ((match-extract-vars (= proc p) . x)
(match-extract-vars p . x)) (match-extract-vars p . x))
((match-extract-vars (quote x) (k ...) i v) ((match-extract-vars (quote x) (k ...) i v)

View file

@ -1,6 +1,6 @@
(cond-expand (cond-expand
(modules (import (chibi match) (only (chibi test) test-begin test test-end))) (modules (import (chibi match) (srfi 9) (only (chibi test) test-begin test test-end)))
(else (load "lib/chibi/match/match.scm"))) (else (load "lib/chibi/match/match.scm")))
(test-begin "match") (test-begin "match")
@ -166,4 +166,20 @@
(((and x (? symbol?)) ..1) x) (((and x (? symbol?)) ..1) x)
(else #f))) (else #f)))
(define-record-type Point
(make-point x y)
point?
(x point-x point-x-set!)
(y point-y point-y-set!))
(test "record positional"
'(1 0)
(match (make-point 0 1)
(($ Point x y) (list y x))))
(test "record named"
'(1 0)
(match (make-point 0 1)
((@ Point (x x) (y y)) (list y x))))
(test-end) (test-end)