微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决使用尾递归实现重复的功能组合

我需要定义一个函数(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适用于任何类型和合成操作,而不仅限于功能合成。

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。