LoginSignup
0
0

More than 1 year has passed since last update.

mapcarを実装してみた - Qiita
maplistを実装してみた - Qiita

今回はmapcを実装してみます。

mapcの挙動を確認する

(defvar *list1* '(1 11 111))
(defvar *list2* '(2 22 222))
(defvar *list3* '(3 33 333))

(format t "~%~A" (mapc (lambda (&rest lists)
                         (format t "~%lists:~A" lists))
                       *list1* *list2* *list3*))
;;; lists:(1 2 3)
;;; lists:(11 22 33)
;;; lists:(111 222 333)
;;; (1 11 111)

mapcの戻り値は引数の最初のリストをそのままでよいようです。高階関数のlambda変数はリストのCARのリストでよいようです。

戻り値を返してみる

(defun my-mapc-aaa (fn &rest lists)
  (car lists))

(format t "~%~A" (my-mapc-aaa nil *list1* *list2* *list3*))
;;; (1 11 111)

これで&restの最初のリストがそのまま返ります。

リストのCARのリストを取り出してみる

高階関数の適用対象となるリストを取り出してみます。

(defun bbb (lists acc)
  (cond ((null lists) acc)
        (t (bbb (cdr lists)
                (append acc `(,(car (car lists))))))))

(defun my-mapc-bbb (fn &rest lists)
  (bbb lists nil))

(format t "~%~A" (my-mapc-bbb nil *list1* *list2* *list3*))
;;; (1 2 3)

正しく取り出されました。

リストのCDRのリストを取り出してみる。

次の再帰の引数となるリストを取り出してみます。

(defun ccc (lists acc)
  (cond ((null lists) acc)
        (t (ccc (cdr lists)
                (append acc `(,(cdr (car lists))))))))

(defun my-mapc-ccc (fn &rest lists)
  (ccc lists nil))

(format t "~%~A" (my-mapc-ccc nil *list1* *list2* *list3*))
;;; ((11 111) (22 222) (33 333))

関数を結合する

(defun ddd (lists acc-car acc-cdr)
  (cond ((null lists) `(,acc-car . ,acc-cdr))
        (t (ddd (cdr lists)
                (append acc-car `(,(car (car lists))))
                (append acc-cdr `(,(cdr (car lists))))))))

(defun my-mapc-ddd (fn &rest lists)
  (ddd lists nil nil))

(format t "~%~A" (my-mapc-ddd nil *list1* *list2* *list3*))
;;; ((1 2 3) (11 111) (22 222) (33 333))

戻りのリストのCARに関数適用の対象となるリスト。CDRに次の再帰に渡すリストが入っています。

再帰的にリストを取り出してみる

(defun eee (lists acc-car acc-cdr)
  (cond ((null lists) `(,acc-car . ,acc-cdr))
        (t (eee (cdr lists)
                (append acc-car `(,(car (car lists))))
                (append acc-cdr `(,(cdr (car lists))))))))

(defun %my-mapc (fn lists acc)
  (cond ((member nil lists) acc)
        (t (let ((tmp (eee lists nil nil)))
             (%my-mapc fn
                       (cdr tmp)
                       (append acc `(,(car tmp))))))))

(defun my-mapc-eee (fn &rest lists)
  (%my-mapc fn lists nil))

(format t "~%~A" (my-mapc-eee nil *list1* *list2* *list3*))
;;; ((1 2 3) (11 22 33) (111 222 333))
(format t "~%~A" (my-mapc-eee nil '(1) *list2* *list3*))
;;; ((1 2 3))

%my-mapcを再帰させています。my-mapc-eeeの戻り値は、関数適用対象のリストのリストです。

高階関数を適用する

(defun fff (lists acc-car acc-cdr)
  (cond ((null lists) `(,acc-car . ,acc-cdr))
        (t (fff (cdr lists)
                (append acc-car `(,(car (car lists))))
                (append acc-cdr `(,(cdr (car lists))))))))

(defun %my-mapc (fn lists acc)
  (cond ((member nil lists) acc)
        (t (let ((tmp (fff lists nil nil)))
             (%my-mapc fn
                       (cdr tmp)
                       (append acc `(,(apply fn (car tmp)))))))))

(defun my-mapc-fff (fn &rest lists)
  (%my-mapc fn lists nil))

(format t "~%~A" (my-mapc-fff #'+ *list1* *list2* *list3*))
;;; (6 66 666)
(format t "~%~A" (my-mapc-fff #'+ '(1) *list2* *list3*))
;;; (6)

これmapcarと同じです。本来mapcは関数適用の結果を返さないため、%my-mapcの蓄積変数が不要です。また、与えたリストの先頭のリストを返すよう変更します。

mapcarをmapcにする

(defun fff (lists acc-car acc-cdr)
  (cond ((null lists) `(,acc-car . ,acc-cdr))
        (t (fff (cdr lists)
                (append acc-car `(,(car (car lists))))
                (append acc-cdr `(,(cdr (car lists))))))))

(defun %my-mapc (fn lists)
  (cond ((member nil lists) t)
        (t (let ((tmp (fff lists nil nil)))
             (apply fn (car tmp))
             (%my-mapc fn (cdr tmp))))))

(defun my-mapc-fff (fn &rest lists)
  (%my-mapc fn lists)
  (car lists))

(format t "~%~A" (my-mapc-fff (lambda (&rest lists)
                                (format t "~%*~A" lists))
                              *list1* *list2* *list3*))
;;; *(1 2 3)
;;; *(11 22 33)
;;; *(111 222 333)
;;; (1 11 111)

%my-mapcの蓄積変数accを取り払います。また、最終的に先頭のリストを返すよう修正します。

整理します

(defun my-mapc (fn &rest lists)
  (labels ((%%my-mapc (lists acc-car acc-cdr)
             (cond ((null lists) `(,acc-car . ,acc-cdr))
                   (t (%%my-mapc (cdr lists)
                                 (append acc-car
                                         `(,(car (car lists))))
                                 (append acc-cdr
                                         `(,(cdr (car lists))))))))
           (%my-mapc (fn lists)
             (cond ((member nil lists) t)
                   (t (let ((tmp (%%my-mapc lists nil nil)))
                        (apply fn (car tmp))
                        (%my-mapc fn (cdr tmp)))))))
    (%my-mapc fn lists)
    (car lists)))

(format t "~%~A" (my-mapc (lambda (&rest lists)
                            (format t "~%*~A" lists))
                          *list1* *list2* *list3*))
;;; *(1 2 3)
;;; *(11 22 33)
;;; *(111 222 333)
;;; (1 11 111)

できあがりました。%my-mapcが蓄積変数を必要としないところがmapcarとの違いです。

最後までご覧いただきありがとうございました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0