(define (compose . fns)
(define (make-chain fn chain)
(lambda args
(call-with-values (lambda () (apply fn args)) chain)))
(reduce make-chain values fns))
Refactorings
No refactoring yet !
Chris Jester-Young
April 22, 2009, April 22, 2009 05:07, permalink
zbigniew from freenode #scheme suggests that "fold" be replaced with "reduce"; this would then strip out the (redundant) "values" call at the start of the function chain. Thanks!
(define (compose . fns)
(define (make-chain fn chain)
(lambda args
(call-with-values (lambda () (apply fn args)) chain)))
(reduce make-chain values fns))
Chris Jester-Young
October 17, 2010, October 17, 2010 16:29, permalink
Just for fun, I decided to make a pure define-only version, just to be slightly easier on the eyes. :-P Not really a serious entry compared to the above, but you get to see defines nested 4 deep!
(define (compose . fns)
(define (make-chain fn chain)
(define (call-chain . args)
(define (call) (apply fn args))
(call-with-values call chain))
call-chain)
(reduce make-chain values fns))
Most people have worked with a simple kind of function composition: one that is essentially (lambda (f g) (lambda (x) (f (g x)))). SRFI 41 (http://srfi.schemers.org/srfi-41/srfi-41.html) describes a more general composition, that takes an arbitrary number of functions, and that allows each function to return multiple values. Here's my version of the same idea, but using "reduce" from SRFI 1 (http://srfi.schemers.org/srfi-1/srfi-1.html), which I think is much cleaner from a functional programming point of view. Feel free to refactor this to make it even more functional. :-)
(Original version used "fold"; thanks to zbigniew on freenode #scheme for suggesting to use "reduce", to remove the redundant "values" call; plus, as Riastradh points out, that makes it tail-recursive also.)