如何实现一个函数,该函数将带有一个参数的任意数量的过程作为输入并返回另一个函数,这是Scheme中这些过程的组合。
例如:
(define (f x) (* x 2))
(define (g x) (* x 3))
(define (h x) (- x))
((comp-func f g h) 1) => -6
((comp-func f g) 1) => 6
((comp-func h) 1) => -1
((comp-func) 1) => 1
答案 0 :(得分:5)
正如所写的那样,这个问题含糊不清,因为我们无法分辨你组成这些函数的顺序。也就是说,我们无法判断是否 ((comp-func fgh)1)计算(f(g(h 1)))或(h(g(f 1))),因为在这种情况下两者都可以达到 -6 。也就是说,这个问题可以通过 fold 或 reduction 来解决;一旦您知道如何编写两个函数,就可以在函数列表中减少该函数。首先,编写两个函数很简单:
(define (compose2 f g)
;; Returns a function that computes (g (f x)).
(lambda (x)
(g (f x))))
现在,将一个函数f叠加到一个带有初始值的列表(x1 x2 ... xn)上意味着计算
(f ... (f (f (f i x1) x2) x3 ...) xn)
编写一个函数列表(f1 f2 f3 f4)只是折叠 compose2 函数,其初始值是标识函数。
(define (identity x)
x)
(define (compose . functions)
(reduce compose2 identity functions))
我会使用订单重要的一些功能,以便我们可以看到结果的差异:
(define (f x) (* x x))
(define (g x) (+ x 3))
(display ((compose f g) 3))
;=> 12 == (g (f 3)) == (3^2)+3
(display ((compose g f) 3))
;=> 36 == (f (g 3)) == (3+3)^2
答案 1 :(得分:1)
一个干净的解决方案是
(define (comp-func . procs)
(define (comp-rec arg procs)
(if (null? procs)
arg
((car procs) (comp-rec arg (cdr procs)))))
comp-rec)
但是,使用此解决方案,您需要像((comp-func f g h) 1 (list f g h))
一样调用它。
如果你在示例中调用它,这个解决方案将会起作用,但是它有点丑陋,因为我们需要使用set!
来更改procs
参数。
(define (comp-func . procs)
(define (comp-rec arg)
(if (null? procs)
arg
(let ((proc (car procs))
(rest (cdr procs)))
(set! procs rest)
(proc (comp-rec arg)))))
comp-rec)