使用尾递归实现重复的功能组合

问题描述

我需要定义一个函数(repeat-write n f),以便 ((repeat-write n f) x)的评估结果为(f (f (... (f x) ...))) 函数nf个应用程序。

例如:

((repeat-write 4 cdr) ’(1 2 3 4 5 6))

评估为

’(5 6)

我不太确定该如何开始。.

解决方法

不使用repeat-compose的{​​{1}}的尾递归解决方案

我们定义了一个尾递归本地帮助函数compose,并在其调用周围放置了一个%repeat-compose,以返回已curryfied函数。

lambda

让我们尝试一下:

(define (repeat-compose n f)
  (define (%repeat-compose n f (acc nil))
    (cond ((<= n 0) acc)
          (else (%repeat-compose (- n 1) f (f acc)))))
  (lambda (x)
    (%repeat-compose n f x)))

它也可以这样定义:

((repeat-compose 3 cdr) '(a b c d e))
;; '(d e)

现在,使用类似的技巧,您可以以尾部递归的方式定义自己的(define ((repeat-compose n f) x) (define (%repeat-compose n f (acc nil)) (cond ((<= n 0) acc) (else (%repeat-compose (- n 1) f (f acc))))) (%repeat-compose n f x))

compose

使用(define (compose . functions) (define (%compose functions acc) (cond ((empty? functions) acc) (else (%compose (cdr functions) ((car functions) acc))))) (lambda (x) (%compose functions x))) ;; or: (define ((compose . functions) x) (define (%compose functions acc) (cond ((empty? functions) acc) (else (%compose (cdr functions) ((car functions) acc))))) (%compose functions x)) ((compose cdr cdr cdr car) '(a b c d e f)) ;; 'd ;; works! 的非递归解决方案

使用composeapply

compose

(define (repeat-compose n f) (apply compose (make-list n f))) 需要一个函数和一个参数列表。 apply通过对元素重复n次来创建列表。

(make-list n el)执行(repeat-compose 5 f),等效于(apply compose (list f f f f f))返回给定参数执行5次(compose f f f f f)的函数。

f

使用((repeat-compose 5 cdr) '(1 2 3 4 5 6 7)) ;; '(6 7) 和显式compose的类似解决方案

lambda
,

首先,我们可以尝试定义

(define ((repeat-compose 4 f) x)
   (f (f (f (f x)))))

还有

(define ((repeat-compose 3 f) x)
   (f (f (f x))))

(define ((repeat-compose 2 f) x)
   (f (f x)))

(define ((repeat-compose 1 f) x)
   (f x))

(define ((repeat-compose 0 f) x)
   x)

这不是有效的球拍。首先,即使相互排斥,我们也无法在球拍中一次拥有多个定义。我们需要将其写为cond

(define ((repeat-compose n f) x)
   (cond
      ((= n 4) (f (f (f (f x)))) )
      ((= n 3) (f (f (f x))) )
      ((= n 2) (f (f x)) )
      ((= n 1) (f x) )
      ((<= n 0) x )))       ;; let's use `<=` here

现在这是有效的球拍,但是当然仍然不能令人满意。如果n大于4怎么办?

但是,等等,您看到那里的图案了吗?当然,它确实像我们想要的那样工作,对于n=4调用函数f 4次,对于n=3调用函数3次,即比n=4少一个时间。所以我们写下来:

(define ((repeat-compose n f) x)
   (cond
      ((= n 4) (f ((repeat-compose (- n 1) f) x)) )
               ;; ------------------------------;
      ((= n 3) (f (f (f x))) )
      ((= n 2) (f (f x)) )
      ((= n 1) (f x) )
      ((<= n 0) x )))

但这也与

相同
(define ((repeat-compose n f) x)
   (cond
      ((= n 4) (f ((repeat-compose (- n 1) f) x)) )
      ((= n 3) (f ((repeat-compose (- n 1) f) x)) )
      ((= n 2) (f ((repeat-compose (- n 1) f) x)) )
      ((= n 1) (f ((repeat-compose (- n 1) f) x)) )
      ((<= n 0) x )))

不是吗?无论如何,4有什么特别之处,为什么我们要人为地要求n为任何特定数字,而不是大于n的任何{用同样的方式?

因此,我们现在可以进一步简化它,注意处理所有 案例,就是这样。

这不是 tail 递归的,是的,但是它是递归的,并且是正确的,这是最重要的。因此,它可以帮助您入门。只需遵循相同的思维方式,并以尾递归的方式写下相应的变换即可。特别是

0

可能会成功。或者,也许您将不得不使用未嵌套的应用程序定义助手内部函数,以使其更明显地 tail -递归。

,

也可以使用for/fold

(define ((repeat-compose n f) x)
  (for/fold ([acc x]) ([i (in-range n)]) (f acc)))

使用它:

> ((repeat-compose 4 cdr) (list 1 2 3 4 5 6))
(list 5 6)
,

power函数正是用于这种事情:

(require relation)
((power cdr 4) '(1 2 3 4 5 6))

=> '(5 6)

power适用于任何类型和合成操作,而不仅限于功能合成。

[公开:我是此实用程序的作者]

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...