Macros cadr、caddr等的可变版本

Macros cadr、caddr等的可变版本,macros,scheme,racket,Macros,Scheme,Racket,我想知道如何在Racket中实现cadr、caddr等的可变版本,而不单独定义每个版本?不 (define (mcadr exp) (mcar (mcdr exp))) 对于可变列表或配对,Racket似乎只支持mcar和mcdr,而不支持“扩展”版本。要做到这一点,我需要知道并擅长宏吗?您可以: (define mcaar (compose mcar mcar)) (define mcadr (compose mcar mcdr)) ;; ... (define mcddddr (c

我想知道如何在Racket中实现cadr、caddr等的可变版本,而不单独定义每个版本?不

(define (mcadr exp)
    (mcar (mcdr exp)))
对于可变列表或配对,Racket似乎只支持mcar和mcdr,而不支持“扩展”版本。要做到这一点,我需要知道并擅长宏吗?

您可以:

(define mcaar (compose mcar mcar))
(define mcadr (compose mcar mcdr))
;; ...
(define mcddddr (compose mcdr mcdr mcdr mcdr))

但这种重复并没有真正的解决办法。即使在Racket源代码中(查看
Racket/src/list.c
),也存在重复,尽管c宏稍微美化了一下。

这里有一个宏解决方案:

#lang racket/base

(require racket/mpair (for-syntax racket/base))

(define-syntax (define-combinations stx)
  (syntax-case stx ()
    [(_ n) (integer? (syntax-e #'n))
     (let ([n (syntax-e #'n)])
       (define options (list (cons "a" #'mcar) (cons "d" #'mcdr)))
       (define (add-options r)
         (apply append
                (map (λ (opt)
                       (map (λ (l) (cons (string-append (car opt) (car l))
                                         (list (cdr opt) (cdr l))))
                            r))
                     options)))
       (define combinations
         (cdddr
          (let loop ([n n] [r '(("" . x))])
            (if (zero? n) r (append r (loop (sub1 n) (add-options r)))))))
       (define (make-name combo)
         (let ([s (string->symbol (string-append "mc" (car combo) "r"))])
           (datum->syntax stx s stx)))
       (with-syntax ([(body ...) (map cdr combinations)]
                     [(name ...) (map make-name combinations)])
         #'(begin (define (name x) body) ...)))]))

(define-combinations 4)
(mcaddr (mlist 1 2 3 4 5))

是的,这可能是不涉及宏的解决方案的最佳选择。