如何解决使用尾递归实现重复的功能组合
我需要定义一个函数(repeat-write n f)
,以便
((repeat-write n f) x)
的评估结果为(f (f (... (f x) ...)))
函数n
有f
个应用程序。
例如:
((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!
的非递归解决方案
使用compose
和apply
。
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 举报,一经查实,本站将立刻删除。