Subject: Re: composing functions and permutations
From: rpw3@rigden.engr.sgi.com (Rob Warnock)
Date: 29 Aug 2001 03:35:31 GMT
Newsgroups: comp.lang.scheme
Message-ID: <9mhnu3$eudt2$1@fido.engr.sgi.com>
Jeffrey Siegal  <jbs@quiotix.com> wrote:
+---------------
| emdpek wrote:
| > (define (compose-many . args)
| >   (if (null? args)
| >       (lambda (y) y)
| >       (let ((first (car args))
| >             (rest (cdr args)))
| >         (lambda (x) (first ((apply compose-many rest) x))))))
| 
| A better solution is:
| (define (compose-many . args)
|   (lambda (x)
|     (let loop ((args args))
|       (if (null? args)
|           x
|           (let ((first (car args))
|                 (rest (cdr args)))
|              (first (loop rest)))))))
+---------------

Well, the only problems is that neither of your solutions permit the
last function (first applied) to accept multiple arguments, as in:

	> (define 3rd-arg (compose car cdr cdr list))
	> (3rd-arg 0 1 2 3 4)
	2
	> 

"Compose" was discussed at length back in May of this year, and
the final version that seemed most useful to me was Al Petrofsky's
[a variant of the one by Matthias Blume]:

	(define (compose . procs)
	  (if (null? procs)
	      values
	      (lambda args
		(call-with-values
		  (lambda () (apply (apply compose (cdr procs)) args))
		  (car procs)))))

This has the following advantages:

- Allows the last function to take multiple arguments, as shown above,
  or as in this example:

	> (define euclidean-metric
	    (compose sqrt
		     (curry apply +)
		     (curry map (curry-r expt 2))
		     list))
	> (euclidean-metric 3 4)
	5
	> (euclidean-metric 5 12)
	13
	> (euclidean-metric 1 2 3 4 5)
	7.416198487095663
	>

- Returns "values" when called with no args, which allows (compose)
  to act as the identity function for both single and multiple values,
  on both on the left & right sides:

	> ((compose (compose) reverse (compose) list (compose)) 1 2 3 4)
	(4 3 2 1)
	> 

- Allows the intermediate results to be multiple values.

	> (define list->values (curry apply values))
	> (define euclidean-metric
	    (compose sqrt + list->values (curry map (curry-r expt 2)) list))
	> (euclidean-metric 3 4)
	5
	>


-Rob

p.s. "curry" & "curry-r" left as an exercise for the reader...  ;-}

-----
Rob Warnock, 30-3-510		<rpw3@sgi.com>
SGI Network Engineering		<http://reality.sgi.com/rpw3/>
1600 Amphitheatre Pkwy.		Phone: 650-933-1673
Mountain View, CA  94043	PP-ASEL-IA

[Note: aaanalyst@sgi.com and zedwatch@sgi.com aren't for humans ]