我尝试制作自己的(撰写)功能,但我无法通过它。
需要按以下方式工作:
让我们称该函数为“manual”——manual 需要接受两个参数,并且它必须以一种方式组合它们,以便以后我们可以这样调用我们的 manual:
((manual func1 func2) 1)
(因此 manual 的输出需要是一个过程)
所以如果 func2 将输入乘以 2,并且 func1 将其提高到三次方,那么
((manual func1 func2) 1)
的输出应该是 8
(( 2*1)^3
)
我试过这样写函数:
(define (manual func1 func2)
(func1 (func2)) ; or f(g), or many other combinations of parenthesis
)
但不幸的是,我无法想到组成这两个。
所以我想它需要更抽象/复杂一点,而不仅仅是一些带有括号的操作。
我想要一个函数,
manual
,它接受两个函数,f
和 g
-
(define (manual f g)
...)
它应该返回一个函数,调用它
composition
-
(define (manual f g)
(define (composition ...)
...)
composition)
当
composition
应用于参数arg
时,它应该返回f
应用于arg
的结果,其中g
应用于f
的结果-
(define (manual f g)
(define (composition arg)
(g (f arg)))
composition)
让我们测试一下-
((manual
(lambda (x) (+ x 1))
(lambda (x) (* x 2)))
3)
8 ; (3 + 1) * 2
如果
composition
不需要名字就好了。 lambda
允许我们定义一个无名的匿名过程 -
(define (manual f g)
(lambda (arg)
(g (f arg))))
如果我想让组合接受多个参数,我可以使用
apply
将 f
应用于所有 args
-
(define (manual f g)
(lambda args
(g (apply f args))))
((manual * add1) 10 20)
201 ; (10 * 20) + 1
如果我想要
manual
接受任意数量的功能,我可以使用 left fold - 重写组合以按顺序应用所有功能
(define (manual f . more)
(lambda args
(foldl (lambda (f x) (f x))
(apply f args)
more)))
((manual * add1 add1 add1 add1 add1) 10 20)
205 ; (((((10 * 20) + 1) + 1) + 1) + 1) + 1
上述特殊行为被赋予序列中的第一个函数。如果我想让
manual
通用,我可以要求调用者处理专门的行为 -
(define (manual . funcs)
(lambda (init)
(foldl (lambda (f x) (f x))
init
funcs)))
((manual
(curry apply *) ; specific behaviour
add1
add1
add1
add1
add1)
(list 10 20)) ; multiple arguments collected in a list
205 ; (((((10 * 20) + 1) + 1) + 1) + 1) + 1
@PeterWinton 指出 typical compose function 将按 right-to-left 顺序应用函数。我们上面写的
manual
过程应用它们 left-to-right。了解其中的区别以及在实践中被认为是常见的是值得的。写manual
来反映这种行为仍然是读者的练习。
当您调用
(manual f g)
时,您想要获得一个可以调用更多参数的函数:
((manual f g) 0 1 2 3)
让我们先简化这个要求,只接受一个参数:
((manual f g) 0)
为了获得一个参数的函数,你写一个lambda形式:
(lambda (v) ...)
所以你可能会写以下内容:
(define (manual f g)
(lambda (v) ...))
如果你认为你应该能够填写剩余的代码。