LoginSignup
0
0

More than 1 year has passed since last update.

maplを実装してみた

Last updated at Posted at 2021-08-18

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

maplの挙動を確認してみる

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

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

高階関数に渡される引数はCDRのリストです。戻り値はmaplの引数の最初のリストがそのまま返ります。

hyperspecを確認してみる

CLHS: Function MAPC, MAPCAR, MAPCAN, MAPL...

Syntax:
mapc function &rest lists+ => list-1
mapcar function &rest lists+ => result-list
mapcan function &rest lists+ => concatenated-results
mapl function &rest lists+ => list-1
maplist function &rest lists+ => result-list
mapcon function &rest lists+ => concatenated-results

Descriptionを抜粋します。

maplistは、関数がリストの連続したサブリストに適用されること以外は、mapcarと似ています。関数は、まずリスト自体に適用され、次に各リストのcdrに適用され、さらに各リストのcdrのcdrに適用される、というように適用されます。

mapl は、関数を適用した結果が累積されないことを除けば、maplist と似ています。list-1 が返されます。

反復処理は,最も短いリストがなくなると終了し,他のリストの過剰な要素は無視されます。

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

高階関数のlambda引数となるCDRのリストを取り出してみます。

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

(defun my-mapl-aaa (fn &rest lists)
  (aaa lists nil))

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

正しく取り出せました。

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

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

(defun %my-mapl (fn lists acc)
  (cond ((member nil lists) acc)
        (t (%my-mapl fn
                     (bbb lists nil)
                     (append acc `(,lists))))))

(defun my-mapl-bbb (fn &rest lists)
  (%my-mapl fn lists nil))

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

CDRのリストのリストが取り出されました。

関数を適用してみる

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

(defun %my-mapl (fn lists acc)
  (cond ((member nil lists) acc)
        (t (apply fn lists)
           (%my-mapl fn
                     (ccc lists nil)
                     (append acc `(,lists))))))

(defun my-mapl-ccc (fn &rest lists)
  (%my-mapl fn lists nil))

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

正しく高階関数が適用されました。しかし、これはmaplistと同じ挙動、むしろmaplistです。

maplistをmaplにする

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

(defun %my-mapl (fn lists)
  (cond ((member nil lists) t)
        (t (apply fn lists)
           (%my-mapl fn (ccc lists nil)))))

(defun my-mapl-ccc (fn &rest lists)
  (%my-mapl fn lists)
  (car lists))

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

%my-maplの蓄積変数accを除外し、高階関数の適用結果を蓄積しないよう変更します。また、最終的な戻り値をリストの先頭のリストに変更します。

整える

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

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

できました。次回はmapcanを実装します。

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

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