maplistを実装してみた
いつもお世話になるmap系の関数たち。
基本的なmap系関数を実装して、理解してしまおうというのがこの記事の趣旨です。
mapcarを実装してみた - Qiita
に引き続いてmaplistを実装してみます。
maplistの動作を確認する
(defvar *list1* '(1 11 111))
(defvar *list2* '(2 22 222))
(defvar *list3* '(3 33 333))
(format t "~%~A" (maplist (lambda (x y z)
(format t "~%x:~A y:~A z:~A" x y z))
*list1* *list2* *list3*))
;;; x:(1 11 111) y:(2 22 222) z:(3 33 333)
;;; x:(11 111) y:(22 222) z:(33 333)
;;; x:(111) y:(222) z:(333)
;;; (NIL NIL NIL)
リストのCDRをlambda引数として再帰的に高階関数を呼び出す。次の再帰に渡すCDRのリストが生成できれば、それに関数適用するだけなのでmapcarと比べると単純です。
次の再帰に渡すリストを生成する
(defun aaa (list acc)
(cond ((null (car list)) acc)
(t (aaa (cdr list)
(append acc `(,(cdr (car list))))))))
(defun my-maplist-aaa (fn &rest lists)
(aaa lists nil))
(format t "~%~A" (my-maplist-aaa nil *list1* *list2* *list3*))
;;; ((11 111) (22 222) (33 333))
最初の呼び出し時点で、次の呼び出しの引数となるリストが取得できています。
関数適用の対象となるリストを蓄積してみる
(defun bbb (list acc)
(cond ((null (car list)) acc)
(t (bbb (cdr list)
(append acc `(,(cdr (car list))))))))
(defun %my-maplist (fn lists acc)
(cond ((null (car lists)) acc)
(t (%my-maplist fn
(bbb lists nil)
(append acc `(,lists))))))
(defun my-maplist-bbb (fn &rest lists)
(%my-maplist fn lists nil))
(format t "~%~A" (my-maplist-bbb nil *list1* *list2* *list3*))
;;; (((1 11 111)
;;; (2 22 222)
;;; (3 33 333))
;;; ((11 111)
;;; (22 222)
;;; (33 333))
;;; ((111)
;;; (222)
;;; (333)))
%my-maplistが呼び出された際、引数として渡ってきたリストに関数を適用するため、リストをそのまま蓄積しているだけです。
関数を適用してみる
(defun ccc (list acc)
(cond ((null (car list)) acc)
(t (ccc (cdr list)
(append acc `(,(cdr (car list))))))))
(defun %my-maplist (fn lists acc)
(cond ((null (car lists)) acc)
(t (%my-maplist fn
(ccc lists nil)
(append acc `(,(apply fn lists)))))))
(defun my-maplist-ccc (fn &rest lists)
(%my-maplist fn lists nil))
(format t "~%~A" (my-maplist-ccc (lambda (x y z)
(format t "~%x:~A y:~A z:~A" x y z))
*list1* *list2* *list3*))
;;; x:(1 11 111) y:(2 22 222) z:(3 33 333)
;;; x:(11 111) y:(22 222) z:(33 333)
;;; x:(111) y:(222) z:(333)
;;; (NIL NIL NIL)
hyperspecのsampleを適用してみる
CLHS: Function MAPC, MAPCAR, MAPCAN, MAPL...
(maplist #'append '(1 2 3 4) '(1 2) '(1 2 3))
=> ((1 2 3 4 1 2 1 2 3) (2 3 4 2 2 3))
(maplist #'(lambda (x) (cons 'foo x)) '(a b c d))
=> ((FOO A B C D) (FOO B C D) (FOO C D) (FOO D))
(maplist #'(lambda (x) (if (member (car x) (cdr x)) 0 1)) '(a b a c d b c))
=> (0 0 1 0 1 1 1)
;An entry is 1 if the corresponding element of the input
; list was the last instance of that element in the input list.
(format t "~%~A" (my-maplist-ccc #'append '(1 2 3 4) '(1 2) '(1 2 3)))
;;; ((1 2 3 4 1 2 1 2 3) (2 3 4 2 2 3) (3 4 3) (4))
(format t "~%~A" (my-maplist-ccc #'(lambda (x)
(cons 'foo x))
'(a b c d)))
;;; ((FOO A B C D) (FOO B C D) (FOO C D) (FOO D))
(format t "~%~A" (my-maplist-ccc #'(lambda (x)
(if (member (car x) (cdr x)) 0 1))
'(a b a c d b c)))
;;; (0 0 1 0 1 1 1)
最初のテストの結果が一致しません。それ以外は一致しました。
不具合を修正する
%my-maplistが呼び出された際、listsにNILが見つかった時点で停止してしまえば良いようです。memberでNILを探します。ちなみに、findではNILの検出ができないようです。
(defun ddd (list acc)
(cond ((null (car list)) acc)
(t (ddd (cdr list)
(append acc `(,(cdr (car list))))))))
(defun %my-maplist (fn lists acc)
(cond ;;;((null (car lists)) acc)
((member nil lists) acc)
(t (%my-maplist fn
(ddd lists nil)
(append acc `(,(apply fn lists)))))))
(defun my-maplist-ddd (fn &rest lists)
(%my-maplist fn lists nil))
(format t "~%~A" (my-maplist-ddd (lambda (x y z)
(format t "~%x:~A y:~A z:~A" x y z))
*list1* *list2* '(3 33)))
;;; x:(1 11 111) y:(2 22 222) z:(3 33)
;;; x:(11 111) y:(22 222) z:(33)
;;; (NIL NIL)
(format t "~%~A" (my-maplist-ddd #'append '(1 2 3 4) '(1 2) '(1 2 3)))
;;; ((1 2 3 4 1 2 1 2 3) (2 3 4 2 2 3))
整える
(defun my-maplist (fn &rest lists)
(labels ((%%my-maplist (list acc)
(cond ((null (car list)) acc)
(t (%%my-maplist (cdr list)
(append acc `(,(cdr (car list))))))))
(%my-maplist (fn lists acc)
(cond ((member nil lists) acc)
(t (%my-maplist fn
(%%my-maplist lists nil)
(append acc `(,(apply fn lists))))))))
(%my-maplist fn lists nil)))
(format t "~%~A" (my-maplist (lambda (x y z)
(format t "~%x:~A y:~A z:~A" x y z))
*list1* *list2* '(3 33)))
;;; x:(1 11 111) y:(2 22 222) z:(3 33)
;;; x:(11 111) y:(22 222) z:(33)
;;; (NIL NIL)
maplistが出来上がりました。次回は、mapcをやりましょうかね。
Author And Source
この問題について(maplistを実装してみた), 我々は、より多くの情報をここで見つけました https://qiita.com/inutomo0123/items/6563bdd140ac13f09ec7著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .