Pau*_*rth 9 scheme functional-programming
我试图在Scheme中找到多参数"compose"的"最佳"实现(我知道它在某些实现中是内置的,但我假设目前我正在使用没有这个的那个).
对于2参数的组合函数,我有这个:
(define compose
(lambda (f g)
(lambda x
(f (apply g x)))))
Run Code Online (Sandbox Code Playgroud)
这样做的好处是,如果最右边的函数需要额外的参数,那么它们仍然可以通过组合函数传递.这具有令人满意的特性,即在某事物之上组成身份功能不会改变功能.
例如:
(define identity
(lambda (x) x))
(define list1
(compose identity list))
(define list2
(compose identity list1))
(list2 1 2 3)
> (1 2 3)
Run Code Online (Sandbox Code Playgroud)
现在做一个"n-argument"compose我可以这样做:
(define compose-n
(lambda args
(foldr compose identity args)))
((compose-n car cdr cdr) '(1 2 3))
> 3
Run Code Online (Sandbox Code Playgroud)
但这不再保留那个漂亮的"身份"属性:
((compose-n identity list) 1 2 3)
> procedure identity: expects 1 argument, given 3: 1 2 3
Run Code Online (Sandbox Code Playgroud)
问题是用于foldr命令的"初始"函数.它已建成:
(compose identity (compose list identity))
Run Code Online (Sandbox Code Playgroud)
所以......我不确定解决这个问题的最佳方法."foldl"似乎是自然更好的选择,因为我想从左边的 "身份"开始而不是正确 ...
但是一个天真的实现:
(define compose-n
(lambda args
(foldl compose identity args)))
Run Code Online (Sandbox Code Playgroud)
哪个有效(必须颠倒功能应用程序的顺序):
((compose-n cdr cdr car) '(1 2 3))
> 3
Run Code Online (Sandbox Code Playgroud)
没有解决问题,因为现在我最终不得不把身份功能放在左边!
((compose-n cdr cdr car) '(1 2 3))
> procedure identity: expects 1 argument, given 3: 1 2 3
Run Code Online (Sandbox Code Playgroud)
就像,我需要使用"foldr"但需要一些不同于身份功能的"初始"值...或更好的身份功能?显然我在这里很困惑!
我想实现它而不必编写一个明确的尾递归"循环"...似乎应该有一个优雅的方法来做到这一点,我只是卡住了.
(define (compose . fns)
(define (make-chain fn chain)
(lambda args
(call-with-values (lambda () (apply fn args)) chain)))
(reduce make-chain values fns))
Run Code Online (Sandbox Code Playgroud)
这不是火箭科学:当我在 #scheme IRC 频道上发布此内容时,Eli指出这是compose. :-)(作为奖励,它也适用于您的示例。)