Mapping a function to a dotted pair

Viewed 93

I want to map a function, (lambda (x) (+ x 1)), to a dotted pair '(1 . 2), to get another dotted pair, '(2 . 3). I have tested the below code to no avail:

(defun mapdot (func coll)
  ((funcall func (car coll)) . (funcall func (cdr coll))))
ELISP> (mapdot (lambda (x) (+ x 1)) '(1 . 2))
*** Eval error ***  Invalid function: (funcall func (car coll))

How can I achieve such behavior?

2 Answers

You had problems with your first attempt because it tries to use (funcall func (car coll)) as the name of a function to call - which of course doesn't work. To make the mistake clearer, it's as if you were doing this:

ELISP> ((list))
*** Eval error ***  Invalid function: (list)

The solution would be to either use cons or a quasiquote:

ELISP> (defun mapdot (func coll)
         (cons (funcall func (car coll)) (funcall func (cdr coll))))
mapdot
ELISP> (mapdot (lambda (x) (+ x 1)) '(1 . 2))
(2 . 3)
ELISP> (defun mapdot (func coll)
         `(,(funcall func (car coll)) . ,(funcall func (cdr coll))))
mapdot
ELISP> (mapdot (lambda (x) (+ x 1)) '(1 . 2))
(2 . 3)

There had been an easy solution I overlooked since I was reluctant to switch to an imperative style: to create a dummy list and manually set the car and cdr of it.

(defun mapdot (func coll)
  (let ((temp-list '(1 2)))
    (progn
      (setf (car temp-list) (funcall func (car coll)))
      (setf (cdr temp-list) (funcall func (cdr coll)))
      temp-list)))

Now it runs just fine:

ELISP> (mapdot (lambda (x) (+ x 1)) '(1 . 2))
(2 . 3)
Related