#:g1: defrecの紹介

Posted 2014-08-19 06:20:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の231日目です。

defrecとはなにか

 defrecは、Robert Smith氏作の再帰する関数を定義するためのユーティリティです。

パッケージ情報

パッケージ名defrec
Quicklisp
Quickdocsdefrec | Quickdocs
CL Test Grid: ビルド状況defrec | CL Test Grid

インストール方法

(ql:quickload :defrec)

試してみる

 どんな関数があるかは、Quickdocsで確認できます。

 といっても定義はdefrec一つのみです。
主に相互呼び出しの再帰関数の定義に用いることを意図しているようですが、defrecマクロがしていることは、ローカル関数を作って、それを大域関数の補助関数とする、というものです。
一度labelsで定義したものをfletで包み、それをまたdefunで大域定義としていますが、fletは何のためなのでしょう。

(defrec:defrec
  (fib (n)
    (fib1 n 1 0))
  (fib1 (n a1 a2)
    (cond ((zerop n) a2)
          ((= 1 n) a1)
          (T (fib1 (1- n) (+ a1 a2) a1)))))
;==>
(LABELS ((FIB (N)
           (FIB1 N 1 0))
         (FIB1 (N A1 A2)
           (COND ((ZEROP N) A2) ((= 1 N) A1) (T (FIB1 (1- N) (+ A1 A2) A1)))))
  (FLET ((#:FIB1221 (N)
           (FIB N))
         (#:FIB11222 (N A1 A2)
           (FIB1 N A1 A2)))
    (DECLARE (INLINE #:FIB1221 #:FIB11222))
    (DEFUN FIB (N) (#:FIB1221 N))
    (DEFUN FIB1 (N A1 A2) (#:FIB11222 N A1 A2)))
  '(FIB FIB1))

(fib 100) ;=> 354224848179261915075

 ドキュメントにあるコード例をみて思いましたが、多分

(labels ((even (x)
           (declare (type unsigned-byte x))
           (if (zerop x)
               t
               (odd (1- x))))
         (odd (x)
           (declare (type unsigned-byte x))
           (if (zerop x)
               nil
               (even (1- x)))))
  (setf (values (fdefinition 'even)
                (fdefinition 'odd))
        (values #'even #'odd)))

 のようなものを、

(defrec:defrec
  (even (x)
    (declare (type unsigned-byte x))
    (if (zerop x) t (odd (1- x))))
  (odd (x)
    (declare (type unsigned-byte x))
    (if (zerop x) nil (even (1- x)))))

のように、すっきり書くことを意図しているのかなと思いました。

まとめ

 今回は、defrecを紹介してみました。
今回も一発物でした。even/oddのような関係の関数の定義は殆どないと思いますが、ローカル関数を定義しつつ大域でも呼び出したいような場合には便利かもしれません。

comments powered by Disqus