On Lisp 復習

つづき(d:id:Nobuhisa:20080120:1200761083)

5.2 直交性

CL-USER 1 > (defvar *!equivs* (make-hash-table))
*!EQUIVS*

CL-USER 2 > 
(defun ! (fn)
  (or (gethash fn *!equivs*) fn) )
!

CL-USER 3 > 
(defun def! (fn fn!)
  (setf (gethash fn *!equivs*) fn!) )
DEF!

CL-USER 4 > (def! #'remove-if #'delete-if)
#<Function DELETE-IF 2021134A>

CL-USER 5 > (setq a '(1 2 3 4 5 6))
(1 2 3 4 5 6)

CL-USER 6 > (setq a
                  (funcall (! #'remove-if) #'oddp a) )
(2 4 6)

関係ないけど,equivsって何語・・・?(辞書とgoogleさんに聞いてみたけど良くわからず...
あと,!関数は本当ならマクロの方が効率的だと書いてあった。こんな感じになるのかな・・・

CL-USER >
(defmacro !! (fn &rest args)
  (let ((f (or (gethash (symbol-function fn) *!equivs*) fn)))
    `(funcall ,f ,@args) ))
!!

CL-USER > (macroexpand '(!! remove-if #'oddp a))
(FUNCALL #<Function DELETE-IF 2021134A> (FUNCTION ODDP) A)
T

CL-USER > (setq a
                (!! remove-if #'oddp a))
(2 4 6 8 10)

マクロ初心者なのでやや苦戦した。。。マクロの章が楽しみ。

5.3 関数の値のメモ化

memoize.

CL-USER 1 > 
(defun memoize (fn)
  (let ((cache (make-hash-table :test #'equal)))
    #'(lambda (&rest args)
        (multiple-value-bind (val win) (gethash args cache)
          (if win
              val
            (setf (gethash args cache) (apply fn args)) )))))
MEMOIZE

CL-USER 2 > (setq slowid
                  (memoize #'(lambda (x) (sleep 5) x)) )
#<anonymous interpreted function 217029E2>

CL-USER 3 > (time (funcall slowid 256))
Timing the evaluation of (FUNCALL SLOWID 256)

User time    =        0.000
System time  =        0.000
Elapsed time =        5.000
Allocation   = 14540 bytes
0 Page faults
256

CL-USER 4 > (time (funcall slowid 256))
Timing the evaluation of (FUNCALL SLOWID 256)

User time    =        0.000
System time  =        0.000
Elapsed time =        0.001
Allocation   = 812 bytes
0 Page faults
256

time関数便利だなぁ。