squash@MATH.UFL.EDU (Jonathan King) (01/13/91)
Node (elisp)Mapping Functions of *info* gives this example of
using mapping functions, to define a more complex mapping function
`mapcar*' :
(defun mapcar* (f &rest args)
"Apply FUNCTION to successive cars of all ARGS, until one ends.
Return the list of results."
(cons (apply f (mapcar 'car args)) ; Apply function to CARs.
(let ((rest (mapcar 'cdr args)))
(if (not (memq 'nil rest)) ; If no list is exhausted,
(apply 'mapcar* f rest))))) ; recurse for rest of elements.
(mapcar* 'cons '(a b c) '(1 2 3 4))
=> ((a . 1) (b . 2) (c . 3))
This works, but not in the base case where one or more of
the ARGS is nil.
Perhaps this version is acceptable:
(defun mapcar* (f &rest args)
"Apply FUNCTION to successive cars of all ARGS, until one ends.
Return the list of results."
(if (not(memq 'nil args)) ; If no list is exhausted,
(cons (apply f (mapcar 'car args)) ; Apply function to CARs.
(apply 'mapcar* f (mapcar 'cdr args)) ; Recurse for rest of elements.
)))
Jonathan
PS> I would like to be able to say that I simply read the description
of mapcar* and saw the problem. However, I am trying to learn how to
use mapping function. I copied mapcar* and used in a larger program
and got bitten by the base case...
================
PPS> I would appreciate comments of the form "Does/doesn't work."
"Can be more efficient." on the following mapping function (which is
written as a learning exercise, for me.)
(defun mapcar+ (f &rest args)
"Apply FUNCTION to successive cars of all non-nil ARGS, discarding elements
of ARGS as they become exhausted. Returns the list of results.
Warning: It is best that FUNCTION accept a variable number of
arguments and be symmetric in those arguments."
(setq args (delq nil args))
(if args ; If arguments are left
(cons (apply f (mapcar 'car args)) ; apply function to CARs.
(apply 'mapcar+ f (mapcar 'cdr args)) ; Recurse for rest of elements.
)))
If FUNCTION does not alter its argument(s), can I conclude
that mapcar+ is safe to ARGS since they are first bound up
in a list? Here is an example in lisp-interaction-mode :
(setq lis '(100 -3 200))
(100 -3 200)
(mapcar+
'+
lis
'(10 2 300)
'(0 10 2 3 4)
nil
)
(110 9 502 3 4)
lis
(100 -3 200)
(mapcar+ '+ )
nil
(mapcar+ '+ nil nil)
nil
;;; Now a destructive function, `sort':
(defun sort_ (&rest numbers)
(sort numbers '<)
)
sort_
lis
(100 -3 200)
(mapcar+
'sort_
lis
'(10 2 300)
'(0 10 2 3 4)
nil
)
((0 10 100) (-3 2 10) (2 200 300) (3) (4))
lis
(100 -3 200)