Search code examples
recursioniterationcommon-lispmap-function

Is there a way to implement mapcar in Common Lisp using only applicative programming and avoiding recursion or iteration as programming styles?


I am trying to learn Common Lisp with the book Common Lisp: A gentle introduction to Symbolic Computation. In addition, I am using SBCL, Emacs and Slime.

In chapter 7, the author suggests there are three styles of programming the book will cover: recursion, iteration and applicative programming.

I am interested on the last one. This style is famous for the applicative operator funcall which is the primitive responsible for other applicative operators such as mapcar.

Thus, with an educational purpose, I decided to implement my own version of mapcar using funcall:

(defun my-mapcar (fn xs)
  (if (null xs)
      nil
      (cons (funcall fn (car xs))
            (my-mapcar fn (cdr xs)))))

As you might see, I used recursion as a programming style to build an iconic applicative programming function.

It seems to work:

CL-USER> (my-mapcar (lambda (n) (+ n 1)) (list 1 2 3 4))
(2 3 4 5)

CL-USER> (my-mapcar (lambda (n) (+ n 1)) (list ))
NIL

;; comparing the results with the official one

CL-USER> (mapcar (lambda (n) (+ n 1)) (list ))
NIL

CL-USER> (mapcar (lambda (n) (+ n 1)) (list 1 2 3 4))
(2 3 4 5)

Is there a way to implement mapcar without using recursion or iteration? Using only applicative programming as a style?

Thanks.

Obs.: I tried to see how it was implemented. But it was not possible

CL-USER> (function-lambda-expression #'mapcar)
NIL
T
MAPCAR

I also used Emacs M-. to look for the documentation. However, the points below did not help me. I used this to find the files below:

/usr/share/sbcl-source/src/code/list.lisp
  (DEFUN MAPCAR)
/usr/share/sbcl-source/src/compiler/seqtran.lisp
  (:DEFINE-SOURCE-TRANSFORM MAPCAR)
/usr/share/sbcl-source/src/compiler/fndb.lisp
  (DECLAIM MAPCAR SB-C:DEFKNOWN)

Solution

  • mapcar is by itself a primitive applicative operator (pag. 220 of Common Lisp: A gentle introduction to Symbolic Computation). So, if you want to rewrite it in an applicative way, you should use some other primitive applicative operator, for instance map or map-into. For instance, with map-into:

    CL-USER> (defun my-mapcar (fn list &rest lists)
               (apply #'map-into (make-list (length list)) fn list lists))
    MY-MAPCAR
    CL-USER> (my-mapcar #'1+ '(1 2 3))
    (2 3 4)
    CL-USER> (my-mapcar #'+ '(1 2 3) '(10 20 30) '(100 200 300))
    (111 222 333)