apropos+describe

aproposとdescribeを一緒にしたような関数を作成。
名前はそのままapropos-desc。

aproposを使えば、シンボル一覧が取得できるが、それに(そのシンボルにバインドしている)関数などの簡単な情報(引数、返り値、ドキュメント)も一緒に表示されるようにした。

基本的には、apropos-listの結果にdescribeを適用しただけだが、sbclの標準のdescribe出力は若干量が多すぎることがあるので、自分に必要な情報だけを出力するようにして、一覧性を上げている。

;; 第三引数までは、apropos関数と同様
;; "multiple"を含むシンボルをcommon-lispパッケージから探して、その名前と簡易的な情報を表示する。
> (apropos-desc "multiple" :common-lisp t)
=== multiple-value-bind [:MACRO]===
ARGUMENTS  : (vars value-form &body body)

=== multiple-value-call [:SPECIAL-OPERATOR]===
ARGUMENTS  : (fun &rest args)
ARGS   TYPE: *
RETURN TYPE: ()
DOCUMENT   :
MULTIPLE-VALUE-CALL function values-form*

Call FUNCTION, passing all the values of each VALUES-FORM as arguments,
values from the first VALUES-FORM making up the first argument, etc.

=== multiple-value-list [:MACRO]===
ARGUMENTS  : (value-form)

=== multiple-value-prog1 [:SPECIAL-OPERATOR]===
ARGUMENTS  : (values-form &rest forms)
ARGS   TYPE: *
RETURN TYPE: ()
DOCUMENT   :
MULTIPLE-VALUE-PROG1 values-form form*

Evaluate VALUES-FORM and then the FORMS, but return all the values of
VALUES-FORM.

=== multiple-value-setq [:MACRO]===
ARGUMENTS  : (vars value-form)

=== multiple-values-limit [:CONSTANT]===
TYPE: (integer 0 536870911)
DOCUMENT:
The exclusive upper bound on the number of multiple VALUES that you can
  return.


;; 第四引数にTを指定すれば、一行に収まらないドキュメント(+その他)の二行目以降が省略される
>  (apropos-desc "multiple" :common-lisp t t)
=== multiple-value-bind [:MACRO]===
ARGUMENTS  : (vars value-form &body body)

=== multiple-value-call [:SPECIAL-OPERATOR]===
ARGUMENTS  : (fun &rest args)
ARGS   TYPE: *
RETURN TYPE: ()
DOCUMENT   : MULTIPLE-VALUE-CALL function values-form* .. ;;;

=== multiple-value-list [:MACRO]===
ARGUMENTS  : (value-form)

=== multiple-value-prog1 [:SPECIAL-OPERATOR]===
ARGUMENTS  : (values-form &rest forms)
ARGS   TYPE: *
RETURN TYPE: ()
DOCUMENT   : MULTIPLE-VALUE-PROG1 values-form form* .. ;;;

=== multiple-value-setq [:MACRO]===
ARGUMENTS  : (vars value-form)

=== multiple-values-limit [:CONSTANT]===
TYPE: (integer 0 536870911)
DOCUMENT: The exclusive upper bound on the number of multiple VALUES that you can .. ;;;

定義

(defun print-function-desc (sym one-line &aux (fn (symbol-function sym)))
  (let ((type-spec (sb-kernel:type-specifier (sb-kernel::info :function :type sym))))
    (format t "ARGUMENTS  : ~:[()~;~:*~(~A~)~]~%"
            (sb-kernel:%simple-fun-arglist
             (if (not (typep fn 'generic-function))
                 (sb-kernel::%closure-fun fn)
               fn)))
    (when (listp type-spec)
      (format t "ARGS   TYPE: ~:[()~;~:*~(~A~)~]~%" (second type-spec))
      (format t "RETURN TYPE: ~:[()~;~:*~(~A~)~]~%" (third type-spec)))
    (when #1=(documentation sym 'function)
      (format t "DOCUMENT   :~:[ ~;~%~]~A~%" one-line #1#))))

(defun print-macro-desc (sym one-line &aux (mc (macro-function sym)))
  (format t "ARGUMENTS  : ~:[()~;~:*~(~A~)~]~%" (sb-kernel:%simple-fun-arglist mc))
  (when #1=(documentation sym 'function)
    (format t "DOCUMENT:~:[ ~;~%~]~A~%"   one-line #1#)))

(defun print-variable-desc (sym one-line &aux (val (symbol-value sym)))
  (format t "TYPE: ~(~A~)~%" (type-of val))
  (when #1=(documentation sym 'variable)
    (format t "DOCUMENT:~:[ ~;~%~]~A~%" one-line #1#)))
 
(defun symbol-type (sym)
  (if (fboundp sym)
      (if (macro-function sym)
          :macro
        (if (special-operator-p sym)
            :special-operator
          (if (typep (symbol-function sym) 'generic-function)
              :generic-function
            :function)))
    (if (constantp sym)
        :constant
      :special)))

(defun symbol-boundp (sym)
  (or (boundp sym) (fboundp sym)))

(defun apropos-desc (string-designator &optional package external-only one-line)
  (let ((*print-lines* (if one-line 1 *print-lines*)))
    (dolist (sym (apropos-list string-designator package external-only))
      (when (symbol-boundp sym)
        (format t "~&=== ~(~S~) [~S]===~%" sym (symbol-type sym))
        (case (symbol-type sym)
          ((:function :generic-function :special-operator)
           (print-function-desc sym (not one-line)))
          (:macro
           (print-macro-desc sym (not one-line)))
          ((:constant :special)
           (print-variable-desc sym (not one-line))))
      (terpri))))
  (values))