On Lisp復習

4章に大量に載ってるユーティリティ関数を早く復習しちゃわないと。。
例のごとく書籍とは完全一致してません。
4.3 のつづき(d:id:Nobuhisa:20071128:1196180768)

CL-USER 1 > 
;; 簡易版
(defun flatten1 (x)
  (mapcan #'(lambda (x)
              (if (atom x)
                  (list x)
                (flatten1 x) ))
          x))
FLATTEN1
CL-USER 2 > (flatten1 '(1 (2 3) 4 (5 (6 (7) 8)) 9))
(1 2 3 4 5 6 7 8 9)

CL-USER 3 > 
;; 高速版
(defun flatten2 (x)
  (labels ((rec (x acc)
             (cond ((null x) acc)
                   ((atom x) (cons x acc))
                   (t (rec (car x) (rec (cdr x) acc))) )))
    (rec x nil) ))
FLATTEN2
CL-USER 4 > (flatten2 '(1 (2 3) 4 (5 (6 (7) 8)) 9))
(1 2 3 4 5 6 7 8 9)


;; 簡易版
CL-USER 5 > 
(defun prune1 (test tree)
  (if (atom tree)
      tree
    (mapcar #'(lambda (x) (prune1 test x))
            (remove-if #'(lambda (y)
                           (and (atom y) (funcall test y)) )
                       tree) )))
PRUNE1
CL-USER 6 > (prune1 #'evenp '(1 (2 (3 4) (5 6 7)) 8 9))
(1 ((3) (5 7)) 9)

;; 高速版
CL-USER 7 > 
(defun prune2 (test tree)
  (labels ((rec (tree acc)
             (cond ((null tree) (nreverse acc))
                   ((consp (car tree))
                    (rec (cdr tree)
                         (cons (rec (car tree) nil) acc) ))
                   (t
                    (rec (cdr tree)
                         (if (funcall test (car tree))
                             acc
                           (cons (car tree) acc) ))))))
    (rec tree nil) ))
PRUNE2
CL-USER 8 > (prune2 #'evenp '(1 (2 (3 4) (5 6 7)) 8 9))
(1 ((3) (5 7)) 9)

再帰はちょっぴり慣れてきたけど,二重再帰になると苦しい。
特にprune2は本見ないと書けにゃい。。。


4.4 検索

CL-USER 1 > 
(defun split-if (fn lst)
  (let (acc)
    (do ((src lst (cdr src)))
        ((or (null src) (funcall fn (car src)))
         (values (nreverse acc) src) )
      (push (car src) acc) )))
SPLIT-IF
CL-USER 2 > (split-if #'(lambda (x) (> x 4))
                      (loop for x from 1 to 10 collect x) )
(1 2 3 4)
(5 6 7 8 9 10)

;; やっぱり載せとく
(defun before (x y lst &key (test #'eql))
  (and lst
       (let ((first (car lst)))
         (cond ((funcall test y first) nil)
               ((funcall test x first) lst)
               (t (before x y (cdr lst) :test test)) ))))
BEFORE

CL-USER > (before 'a 'b '(w a w w b))
(A W W B)
CL-USER > (before 'a 'b '(w w a w w))
(A W W)

CL-USER > 
(defun after (x y lst &key (test #'eql))
  (let ((rest (before y x lst :test test)))
    (and rest (member x rest :test test)) ))
AFTER

CL-USER > (after 'a 'b '(x b x a x))
(A X)
CL-USER > (after 'a 'b '(x x a x))
NIL


この辺で寝よう。