Toshと言います。
そんなわけでマクロで遊んでみた結果が下。
MLのパターンマッチをGaucheで。 プロトタイプなのでパターンの解析を実行時にやってたりします。
gosh> (define (tail l) (match l ((_ . xs) => xs))) tail gosh> (tail '(1 2 3)) (2 3) gosh> (define (head l) (match l ('() => #f) ((x . _) => x))) head gosh> (head '(1 2 3)) 1 gosh> (use srfi-9) (#<module srfi-9> #<module gauche.interactive>) gosh> (define-record-type pare (kons x y) pare? (x kar set-kar!) (y kdr)) #f gosh> (match (kons 1 2) ((obj (x 1) (y y)) => y)) 2
(use srfi-1) (define-macro (match target . body) (let ((tsym (gensym)) (sym (gensym))) `(let ((,tsym ,target) (,sym #f)) (cond ,@(map (cut parse-clause <> tsym sym) body))))) (define (parse-clause clause target sym) (cond ((and (eq? (second clause) 'when) (eq? (fourth clause) '=>)) (parse-clause-with-guard (first clause) (third clause) (fifth clause) target sym)) ((eq? (second clause) '=>) (parse-clause-not-guard (first clause) (third clause) target sym)) (else (error "Syntax error!")))) (define (parse-clause-with-guard pat grd expr target sym) (let ((vars (vars-in-pattern pat))) `((begin (set! ,sym (try-match ',pat ,target)) (and ,sym ,(let-vars-in-pattern vars sym grd))) ,(let-vars-in-pattern vars sym expr)))) (define (parse-clause-not-guard pat expr target sym) (let ((vars (vars-in-pattern pat))) `((begin (set! ,sym (try-match ',pat ,target)) ,sym) ,(let-vars-in-pattern vars sym expr)))) (define (try-match pat target) (cond ((eq? pat '_) '()) ((pattern-variable? pat) (list (cons pat target))) ((not-pair? pat) ; constant (if (equal? pat target) '() #f)) ((and (eq? (car pat) 'as) (pattern-variable? (second pat))) ; as (append-when-list (try-match (third pat) target) (list (cons (second pat) target)))) ((eq? (car pat) 'or) (any (cut try-match <> target) (cdr pat))) ((eq? (car pat) 'obj) (apply append-when-list (map (cut try-match-obj-slot <> target) (cdr pat)))) (else ; list (if (pair? target) (append-when-list (try-match (car pat) (car target)) (try-match (cdr pat) (cdr target))) #f)))) (define (try-match-obj-slot pat target) (let ((slot (car pat)) (spat (second pat))) (if (slot-exists? target slot) (try-match spat (slot-ref target slot)) #f))) (define (append-when-list . lists) (if (every list? lists) (apply append lists) #f)) (define (let-vars-in-pattern vars bounds expr) (if (null? vars) expr `(let ((,(car vars) (value-for-var ,bounds ',(car vars)))) ,(let-vars-in-pattern (cdr vars) bounds expr)))) (define (vars-in-pattern pat) (cond ((pair? pat) (append (vars-in-pattern (car pat)) (vars-in-pattern (cdr pat)))) ((pattern-variable? pat) (cons pat '())) (else '()))) (define (pattern-variable? sym) (and (symbol? sym) (not (eq? sym '_)))) (define (value-for-var bounds var) (let ((m (assq var bounds))) (if m (cdr m)))) numero rio