组合其他函数的 Scheme 函数

A Scheme function to compose other functions

我希望创建一个可以将两个函数合二为一的函数。给定 gf,它应该创建一个函数 h 提供 f 的输出作为 g 的输入。这是我的结果:

(define (compose g f)
    (lambda (.args)
        (g (apply f (if (atom? .args) (list .args) .args)))))

以下代码段适用于 compose

(display ((compose add1 add1) 3))

但是,我不明白为什么下面的示例不起作用。我在下面提供了错误消息,并且我使用的是 Chez Scheme 9.5.2。这里的错误可能与 compose 的可变参数性质有关,但这只是一个想法。有谁知道为什么我的第二次测试没有按预期进行?

(define (reduce f lst seed)
    (if (null? lst) seed
        (f (car lst) (reduce f (cdr lst) seed))))

(define product-of-incremented-list
    (compose
        (lambda (lst) (reduce * lst 1))
        (lambda (lst) (map add1 lst))))

(display (product-of-incremented-list '(3 4 5)))
; I was expecting 120, because (3 4 5) -> (4 5 6) and (4 5 6) -> 120
; I'm getting an error instead:
; Exception: incorrect number of arguments to #<procedure at compose.scm:285>

您试图使用 .args 表示“参数列表”,也许与 (lambda (x . more) ...) 类比,但这是不正确的。 .args 和其他任何符号一样只是一个符号,因此您编写了一个函数,它接受一个名为 .args 的参数。然后当你发现你的论点是一个列表时,你 (apply f '(3 4 5))。但是您用于 f 的 lambda 不需要三个参数,它需要一个列表参数。因此错误。

相反,“参数列表”的表达方式是

(lambda args
  ...)

一般来说,你在lambda后面写的就是如何对待输入参数列表。如果你在那里放一个像 (x y) 这样的列表,那么参数列表应该有两个组成部分,xy。对于 (x . more),第一个元素被命名为 x,然后列表的其余部分被命名为 more。如果你只想要列表原样,你只需给它一个名字:这里,args.

你的第二个问题是检查参数是列表还是原子。这很愚蠢:您可以确定它永远是一个列表,因为您没有分解输入参数。所以,

(define (compose f g)
  (lambda args
    (f (apply g args))))