[Openmcl-devel] documentation from the string to the error print

Janusz Podrazik info at mracpublishing.com
Wed Jun 22 03:16:32 PDT 2011


Dear Pascal,

Thanks so much for the in depth explanation.
I had try your suggestions but never got the result I am looking for.

The entire code for the DIAGNOSE-QUIETLY:

;;; ----------------------------------------------------------------------------- 
;;; DIAGNOSE-QUIETLY
;;; -----------------------------------------------------------------------------

(defVar diagnose-verbose t) 
(defVar $cr$ 'nil)
(defVar *compile-diagnose* nil)
(defParameter *current-evaluation* "")

(defun diagnostic (&rest l) 
 (when l (setq *current-evaluation* (car l)))
 (if diagnose-verbose
 (dolist (item l) 
 (if (eql item $cr$)
 (terpri)
 (princ item)))))

(defMacro do-quietly (name &body body) 
 `(let ((temp diagnose-verbose)
 (return-value nil))
 (handler-case 
 (progn
 (setq diagnose-verbose nil)
 (setq return-value (progn , at body))
 (setq diagnose-verbose temp)
 return-value)
 (error (c)
 (princ "ERROR! Check parameters.")
 (princ (documentation ',name 'function))
 (print c)
 (setq diagnose-verbose temp)
 (abort)))))

(defun sum (n) 
"SUM (numbers)
 Returns the sum of the elements in a series of numbers.
 Examples:
 (sum '(1 2 3 4))
 (sum '(1 2 3 -4))"
 (diagnostic "sum" $cr$)
 (do-quietly 'sum
 (reduce #'+ n)))


The diagnostic function print the name and the result: 

(sum '(1 2 3 4)) 
? sum
10

The do-quietly macro suppress the print of the sub 
function (if any) and if error print the documentation string.

The concept is to get the user quick help to resolved 
the error with the arguments.

Maybe the best way would be to have one function doing 
the print of the NAME and result and if error the documentation.
Let say the function name would be DIAGNOSE-QUIETLY.
But I can't find the way to work. Therefore I use
one function for NAME and marcro function for error.

the use would be like:


(defun sum (n)


"SUM (numbers)


 Returns the sum of the elements in a series of numbers.


 Examples:


 (sum '(1 2 3 4))


 (sum '(1 2 3 -4))"


 (diagnose-quietly 'sum


 (reduce #'+ n)))










For now, I am getting Stack overflow.

(sum '(1 2 3 y)) 
ERROR! Check parameters.
> Error: Stack overflow on value stack.
> While executing: symbol-package, in process Listener(13).
> Type cmd-. to abort, cmd-\ for a list of available restarts.
> Type :? for other options.
1 > 

Janusz
--
MRAC Publishing
Janusz Podrazik


On Wednesday, 22 June 2011 at 01:16, Pascal J. Bourguignon wrote:

> Janusz Podrazik <info at mracpublishing.com (mailto:info at mracpublishing.com)> writes:
> 
> > What I am trying to do is to include function documentation from the
> > string to the error print.
> > 
> > (defMacro do-quietly (name &body body) ; with name
> >  `(let ((temp diagnose-verbose)
> >  (return-value nil))
> >  (handler-case 
> >  (progn
> >  (setq diagnose-verbose nil)
> >  (setq return-value (progn , at body))
> >  (setq diagnose-verbose temp)
> >  return-value)
> >  (error (c)
> >  (princ "ERROR! Check Arguments.")
> >  (princ (documentation name 'function))
> >  (print c)
> >  (setq diagnose-verbose temp)
> >  (abort)))))
> > 
> > (defun collect-sum (n)
> >  "COLLECT-SUM (numbers)
> >  Returns the sum of the elements in a series of numbers.
> >  Examples:
> >  (collect-sum '(1 2 3 4)
> >  (collect-sum '(1 2 3 -4))"
> >  (do-quietly 'collect-sum ;function name
> >  (reduce #'+ n)))
> > 
> > 4 > ERROR! Check Arguments.
> > > Error: Unbound variable: name
> > > While executing: collect-sum, in process Listener(13).
> > > Type cmd-. to abort, cmd-\ for a list of available restarts.
> > > Type :? for other options.
> > 
> > whats wrong?
> 
> You wrote a macro that generates code that makes reference to a variable
> named NAME, while no such variable exist.
> 
> The parameters of the macros are known at compilation time only, when
> macro expansion occurs. At run time, the macro doesn't exist anymore,
> and neither do its parameters.
> 
> So you need to insert the name of the function in the code generated:
> 
>  `... (princ (documentation ',name 'function)) ...
> 
> (Remember some function names are lists, so you must quote it for those
> cases).
> 
> 
> Now, your macro has a lot of problems:
> 
>  (defmacro do-quietly (name &body body)
>  `(let ((temp diagnose-verbose)
>  (return-value nil))
>  (handler-case 
>  (progn
>  (setq diagnose-verbose nil)
>  (setq return-value (progn , at body))
>  (setq diagnose-verbose temp)
>  return-value)
>  (error (c)
>  (princ "ERROR! Check Arguments.")
>  (princ (documentation ',name 'function))
>  (print c)
>  (setq diagnose-verbose temp)
>  (abort)))))
> 
> What's this free variable diagnose-verbose?
> If that's a special variable, it should be named *diagnose-verbose*.
> In that case, you can just use a dynamic binding to shadow its value:
> 
>  (defmacro do-quietly (name &body body)
>  `(let ((return-value nil))
>  (handler-case 
>  (let ((*diagnose-verbose* nil))
>  (setq return-value (progn , at body))
>  return-value)
>  (error (c)
>  (princ "ERROR! Check Arguments.")
>  (princ (documentation ',name 'function))
>  (print c)
>  (abort)))))
> 
> Then, bodies may return several values, are you sure you want to throw
> away all but the first? In any case, you should not use SETQ, but LET:
> 
>  (defmacro do-quietly (name &body body)
>  `(handler-case 
>  (let ((*diagnose-verbose* nil))
>  (let ((return-value (progn , at body)))
>  return-value))
>  (error (c)
>  (princ "ERROR! Check Arguments.")
>  (princ (documentation ',name 'function))
>  (print c)
>  (abort))))
> 
> If you wanted to return only the first value, it might be clearer to use
> 
>  (values (progn , at body)) ; values returns as many values as
>  ; arguments it is given, so we see only
>  ; one value is returned here.
> 
> or even:
> 
>  (nth-value 0 (progn , at body)) ; explicitely return just the first value.
> 
> 
> So if I wanted to throw away the other values of the body, I'd write:
> 
>  (defmacro do-quietly (name &body body)
>  `(handler-case 
>  (let ((*diagnose-verbose* nil))
>  (values (progn , at body)))
>  (error (c)
>  (princ "ERROR! Check Arguments.")
>  (princ (documentation ',name 'function))
>  (print c)
>  (abort))))
> 
> but there's really no reason to do it in general, so let's just let body
> return all its values:
> 
>  (defmacro do-quietly (name &body body)
>  `(handler-case 
>  (let ((*diagnose-verbose* nil))
>  , at body)
>  (error (c)
>  (princ "ERROR! Check Arguments.")
>  (princ (documentation ',name 'function))
>  (print c)
>  (abort))))
> 
> 
> 
> On the other hand, diagnose-verbose could be a symbol macro, in which
> case you'd have to use #+clisp ext:letf to bind it instead of cl:let, 
> ext:letf expands to something like:
> 
>  (let ((saved-value diagnose-verbose))
>  (unwind-protect
>  (progn (setf diagnose-verbose nil)
>  (do-something))
>  (setf diagnose-verbose saved-value)))
> 
> so you'd write something similar:
> 
>  (defmacro do-quietly (name &body body)
>  (let ((saved-variable (gensym "SAVED-VALUE-")))
>  `(handler-case 
>  (let ((,saved-variable diagnose-verbose))
>  (unwind-protect
>  (progn
>  (setf diagnose-verbose nil)
>  , at body)
>  (setf diagnose-verbose ,saved-variable)))
>  (error (c)
>  (princ "ERROR! Check Arguments.")
>  (princ (documentation ',name 'function))
>  (print c)
>  (abort)))))
> 
> 
> 
> 
> 
> It is better to use princ for the condition too, if you want a human
> readable error message. You could also use format:
> 
>  (defmacro do-quietly (name &body body)
>  `(handler-case 
>  (let ((*diagnose-verbose* nil))
>  , at body)
>  (error (err)
>  (format t "ERROR! Check Arguments. ~&~A~%~A~%"
>  (documentation ',name 'function) err)
>  (abort))))
> 
> Finally, are you sure you want to call ABORT here? This will probably
> stop the execution of your program, since I doubt you installed an ABORT
> restart. It might be better to not call ABORT, and let the program run
> other tests. You may also want to enter the debugger to better explore
> why the form failed, in the context (you'd rather use HANDLER-BIND in
> this case thought). Or if you just wanted to issue the message, you
> could also re-signal the error (ERROR ERR), so that the next handler has
> a chance of handling it too.
> 
> 
> -- 
> __Pascal Bourguignon__ http://www.informatimago.com/
> A bad day in () is better than a good day in {}.
> 
> _______________________________________________
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com (mailto:Openmcl-devel at clozure.com)
> http://clozure.com/mailman/listinfo/openmcl-devel

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.clozure.com/pipermail/openmcl-devel/attachments/20110622/16d2e7aa/attachment.htm>


More information about the Openmcl-devel mailing list