Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ionic-framework/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scheme 宏来简化递归函数语法_Scheme_Racket - Fatal编程技术网

Scheme 宏来简化递归函数语法

Scheme 宏来简化递归函数语法,scheme,racket,Scheme,Racket,当我学习“计划”和“拍子”时,我发现自己一次又一次地重复这个模式。我有一个递归函数,其中函数的一些参数改变了,但一些参数没有改变。我构建了一个接受所有参数的外部函数,在这个外部函数中定义了一个只接受不断变化的参数的内部函数,并在此基础上重复出现 作为一个具体的例子,这里有一个基于“小阴谋家”中函数练习的案例 是否可以构建宏定义*和运算符(例如竖条),以便我键入: (define* (insert-to-right new old | lat) (cond

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

作为一个具体的例子,这里有一个基于“小阴谋家”中函数练习的案例

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

(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)))]))  

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

您可以编写这样的宏,但也可以使用命名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)))])))

在玩过之后,我构建了一个宏,它可以满足我的需要

(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。

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


谢谢马蒂亚斯。我想知道如果没有一个内部函数或一个命名的let,我怎么能做到这一点。谢谢Sacundim,但我只是使用insert to right作为示例。问题是关于简化一般情况下的语法,在这种情况下,我重复使用一个函数,其中一些参数是不变的,而另一些参数不是不变的。宏使代码更难阅读和排除故障,实际上只有一些东西是绝对需要它们的。例如,(a)添加不计算其所有子表达式的表达式形式,或(b)添加新类型的绑定形式(绑定新变量的表达式)。任何具有副作用的形式,例如:(定义语法规则(增量!X)(set!X(add1 X)),可以使这一经典更清晰:(定义(生成计数器)(定义计数器0)(lambda()(递增!计数器)计数器)(定义计数器1(生成计数器))
(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 (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)))))