return 组合函数的方案函数

Scheme function that return composition of functions

如何实现一个函数,将任意数量的一个参数的过程作为输入,returns另一个函数是这些过程在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

一个干净的解决方案是

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

正如所写,这个问题是模棱两可的,因为我们无法判断您在编写函数时的顺序。也就是说,我们无法判断是否 ((comp-func f g h) 1) 计算 (f (g (h 1)))(h (g (f 1))),因为在这种情况下两者都会计算出 -6。也就是说,这个问题可以通过 foldreduction 来解决;一旦您知道如何组合 两个 函数,您就可以在函数列表上减少该函数。首先,组合两个函数很简单:

(define (compose2 f g)
  ;; Returns a function that computes (g (f x)).
  (lambda (x)
    (g (f x))))

现在,将函数 f 折叠到具有初始值 i 的列表 (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