2

当我学习计划和球拍时,我发现自己一次又一次地重复这种模式。我有一个递归函数,其中函数的某些参数会更改,但某些参数不会。我构建了一个接受所有参数的外部函数,并在其中定义了一个只接受不断变化的参数并在其上重复的内部函数。

作为一个具体的例子,这里有一个基于“The Little Schemer”中的函数练习的案例

;inserts an item to the right of an element in a list   
(define   (insert-to-right new old lat)    
  (define (insert-to-right lat)  
    (cond  
      [(null? lat) lat]  
      [(eq? old (car lat) ) (cons old (cons new (cdr lat)))]  
      [else (cons (car lat) (insert-to-right    (cdr lat)))]))  
    (insert-to-right lat)) 

是否可以构建一个宏定义 * 和一个运算符(例如竖线),以便我输入:

(define*   (insert-to-right new old | lat)      
    (cond  
      [(null? lat) lat]  
      [(eq? old (car lat) ) (cons old (cons new (cdr lat)))]  
      [else (cons (car lat) (insert-to-right    (cdr lat)))]))  

然后这将扩展为第一种形式,所有参数都传递给外部函数,但只有竖线之后的参数传递给内部循环。

4

3 回答 3

8

您可以编写这样的宏,但也可以只使用命名的 let:

(define (insert-to-right new old lat)
  (let loop ([lat lat])
    (cond
      [(null? lat)         lat]  
      [(eq? old (car lat)) (cons old (cons new (cdr lat)))]  
      [else                (cons (car lat) (loop (cdr lat)))])))
于 2012-04-08T20:39:36.540 回答
3

在玩耍之后,我构建了一个可以满足我需求的宏。

(define-syntax-rule 
  (define* (function-name (outer-var ...)  (inner-var ...)) expr ...)
  (define (function-name outer-var ... inner-var ...) 
    (define (function-name inner-var ...)expr ...)
    (function-name inner-var ...)))   


(define*   (insert-to-right [new old] [lat])        
    (cond  
      [(null? lat) lat]  
      [(eq? old (car lat) ) (cons old (cons new (cdr lat)))]  
      [else (cons (car lat) (insert-to-right    (cdr lat)))])) 

> (insert-to-right 11 3 '(1 2 3 4 5 6))
'(1 2 3 11 4 5 6)

在define* 语句中,它不使用内部参数和外部参数之间的分隔符(正如我最初尝试做的那样),而是将define* 语句中的内部参数和外部参数放入单独的列表中,我认为这是更惯用的Scheme/Racket .

于 2012-04-09T02:52:12.993 回答
0

您不应该使用宏来执行此操作。这是高阶函数的教科书案例;特别是,我相信您的示例可以用pair-fold-rightfrom SRFI-1编写。未经测试的代码(我希望这是正确的):

(define (insert-to-right new old lat)
  (pair-fold-right (lambda (pair rest)
                     (if (eq? (car pair) old)
                         (cons (car pair)
                               (cons new rest))
                         pair))
                   '()
                   lat))

;;; Example implementation of pair-fold-right, just for one list—your Scheme system
;;; probably has this as a library function somewhere
(define (pair-fold-right fn init list)
  (if (null? list)
      init
      (fn list (pair-fold-right fn init (cdr list)))))
于 2012-04-10T21:17:43.040 回答