当我学习计划和球拍时,我发现自己一次又一次地重复这种模式。我有一个递归函数,其中函数的一些参数改变但一些参数没有。我构建了一个外部函数,它接受所有参数,并在其中定义一个内部函数,它只接受变化的参数并重复出现。
作为一个具体的例子,一个案例基于“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)))]))
然后这会扩展到第一个表单,所有参数都传递给外部函数,但只传递垂直条传递给内部循环后的参数。
答案 0 :(得分: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)))])))
答案 1 :(得分: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 *语句中的内部和外部参数放入单独的列表中,我认为这些参数更为惯用方案/球拍。
答案 2 :(得分:0)
您不应该使用宏来执行此操作。这是高阶函数的教科书案例;特别是,我相信您的示例可以使用pair-fold-right
from 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)))))