From: Nicholas Sandow
Subject: Returning to top-level on error
Date: 
Message-ID: <43b3b759@duster.adelaide.on.net>
Can Lisp be told not to enter the "break loop" when encountering an 
error, but instead just return to the top-level?

I'm a newbie and I'm typing all kinds of junk into the top-level by way 
of exploration.  I don't want Lisp to enter the break loop when I type 
in something nonsensical - I just want it to describe the problem and 
return to top-level.

If this cannot be done in ANSI CL, then a means for doing it in clisp 
would be most helpful.

thankyou,
Nick.

From: Pascal Bourguignon
Subject: Re: Returning to top-level on error
Date: 
Message-ID: <87mzik2lza.fsf@thalassa.informatimago.com>
Nicholas Sandow <······@internode.on.net> writes:

> Can Lisp be told not to enter the "break loop" when encountering an
> error, but instead just return to the top-level?

(ignore-errors (do-something))

> I'm a newbie and I'm typing all kinds of junk into the top-level by
> way of exploration.  I don't want Lisp to enter the break loop when I
> type in something nonsensical - I just want it to describe the problem
> and return to top-level.
>
> If this cannot be done in ANSI CL, then a means for doing it in clisp
> would be most helpful.

You can write your own REPL:

(defmacro handling-errors (&body body)
  `(HANDLER-CASE (progn ,@body)
     (t (ERR) (format t "~&~S~%~A~%" err err))))

(defun repl ()
  (do ((hist 1 (1+ hist))
       (+eof+ (gensym)))
      (nil)
    (format t "~%~A[~D]> " (package-name *package*) hist)
    (handling-errors
     (setf +++ ++   ++ +   + -   - (read *standard-input* nil +eof+))
     (when (or (eq - +eof+)
               (member - '((quit)(exit)(continue)) :test (function equal)))
       (return-from repl))
     (setf /// //   // /   / (multiple-value-list (eval -)))
     (setf *** **   ** *   * (first /))
     (format t "~& --> ~{~S~^ ;~%     ~}~%" /))))

[157]> (repl)

COMMON-LISP-USER[1]> (/ 1 0)
#<SYSTEM::SIMPLE-DIVISION-BY-ZERO #x204D3786>
division by zero


COMMON-LISP-USER[2]> 

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

What is this talk of 'release'? Klingons do not make software 'releases'.
Our software 'escapes' leaving a bloody trail of designers and quality
assurance people in it's wake.
From: Steven M. Haflich
Subject: Re: Returning to top-level on error
Date: 
Message-ID: <pvptf.39849$dO2.4027@newssvr29.news.prodigy.net>
Pascal Bourguignon wrote:

>>Can Lisp be told not to enter the "break loop" when encountering an
>>error, but instead just return to the top-level?
> 
> (ignore-errors (do-something))

This is appropriate for almost any normal circumstance, but isn't
quite bulletproof.

ignore-errors is roughly equivalent to a handler-case for conditions
of type cl:error wrapped around the body.  In CL errors are usually
signalled with the error function, which is defined approximately

(defun error (datum &rest arguments)
   (let ((condition (_coerce-to-condition_ frob rest)))
     (signal condition)
     (invoke-debugger condition)))

The _coerce-to-condition_ function implements the hairy way condition
signalling functions interpret their arguments either to be a condition
or to be a designator for a condition.  The condition is signalled, and
if some surrounding handler handles it (by not returning) the debugger
is not called.  But if no surrounding handler handles the condition then
the debugger will be entered.

Here's an example how ignore-errors might not be adequate:

  cl-user(5): (ignore-errors
               (error (make-condition 'simple-error
                        :format-control "Hello, world!"
                        :format-arguments nil)))
  nil
  #<simple-error @ #x100178a5f2>
  cl-user(6): (ignore-errors
               (error (make-condition 'simple-warning
                        :format-control "Hello, world!"
                        :format-arguments nil)))
  Error: Hello, world!
    [condition type: simple-warning]

  Restart actions (select using :continue):
   0: Return to Top Level (an "abort" restart).
   1: Abort entirely from this (lisp) process.

I think Pascal's answer is correct and quite sufficient in normal
circumstances and in the way the condition system is normally used,
but it isn't bulletproof in the face of strangely written
application code.
From: Joe Marshall
Subject: Re: Returning to top-level on error
Date: 
Message-ID: <1136011809.511377.10320@g44g2000cwa.googlegroups.com>
Steven M. Haflich wrote:
> Pascal Bourguignon wrote:
>
> >>Can Lisp be told not to enter the "break loop" when encountering an
> >>error, but instead just return to the top-level?
> >
> > (ignore-errors (do-something))
>
> This is appropriate for almost any normal circumstance, but isn't
> quite bulletproof.

It ignores too much on Allegro Common Lisp, which seems to consider
control-C to be an error.

(defmacro ignore-errors (&rest forms)
  (let ((block-name (gensym "IGNORE-ERRORS-BLOCK-")))
    `(BLOCK ,block-name
       (HANDLER-BIND (#+allegro (EXCL:INTERRUPT-SIGNAL #'ERROR)

                      (ERROR (LAMBDA (CONDITION)
                                (RETURN-FROM ,block-name
                                  (values NIL CONDITION)))))
         ,@forms))))
From: Christophe Rhodes
Subject: Re: Returning to top-level on error
Date: 
Message-ID: <sqwthlogki.fsf@cam.ac.uk>
"Steven M. Haflich" <···@alum.mit.edu> writes:

> I think Pascal's answer is correct and quite sufficient in normal
> circumstances and in the way the condition system is normally used,
> but it isn't bulletproof in the face of strangely written
> application code.

Isn't the way to disable the debugger, well, to disable the debugger,
rather than to try to handle conditions of various types?

(defun probably-disable-debugger (c f)
  (declare (ignore f))
  (abort c))
(setf *debugger-hook* #'probably-disable-debugger)

Christophe
From: Thomas F. Burdick
Subject: Re: Returning to top-level on error
Date: 
Message-ID: <xcvirt5mq1v.fsf@conquest.OCF.Berkeley.EDU>
Christophe Rhodes <·····@cam.ac.uk> writes:

> "Steven M. Haflich" <···@alum.mit.edu> writes:
> 
> > I think Pascal's answer is correct and quite sufficient in normal
> > circumstances and in the way the condition system is normally used,
> > but it isn't bulletproof in the face of strangely written
> > application code.
> 
> Isn't the way to disable the debugger, well, to disable the debugger,
> rather than to try to handle conditions of various types?
> 
> (defun probably-disable-debugger (c f)
>   (declare (ignore f))
>   (abort c))
> (setf *debugger-hook* #'probably-disable-debugger)

That will work, except for explicit calls to CL:BREAK, and assuming
your implementation doesn't do something annoying, like have another
*debugger-hook*-alike.  Man, that took me long enough to figure out.
So, add to that:

  #+sbcl (setf sb-ext:*invoke-debugger-hook* #'probably-disable-debugger)

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | Free Mumia Abu-Jamal! |
     ,--'    _,'   | Abolish the racist    |
    /       /      | death penalty!        |
   (   -.  |       `-----------------------'
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Steven M. Haflich
Subject: Re: Returning to top-level on error
Date: 
Message-ID: <0mFtf.7838$oW.3157@newssvr11.news.prodigy.com>
Christophe Rhodes wrote:

> Isn't the way to disable the debugger, well, to disable the debugger,
> rather than to try to handle conditions of various types?
> 
> (defun probably-disable-debugger (c f)
>   (declare (ignore f))
>   (abort c))
> (setf *debugger-hook* #'probably-disable-debugger)

Well, invoking an abort restart returns to the innermost
reasonable command loop.  This isn't generally the same thing
as wrapping an ignore-errors around some smaller block of code,
allowing that code silently to continue execution if the wrapped
code fails for any reason.

It all depends which is the desired behavior in the particular
context.

Globally disabling the debugger might be a very baaad thing to do.
Some debuggers have the ability to recover from otherwise fatal
errors, such as setting one of the cl special variables to some
illegal value.  The debugger might upon entry check these variables
for reasonableness and lambda bind a reasonable default, allowing
debugging to be done.
From: Pascal Costanza
Subject: Re: Returning to top-level on error
Date: 
Message-ID: <41hvlpF181ispU1@individual.net>
Nicholas Sandow wrote:
> Can Lisp be told not to enter the "break loop" when encountering an 
> error, but instead just return to the top-level?
> 
> I'm a newbie and I'm typing all kinds of junk into the top-level by way 
> of exploration.  I don't want Lisp to enter the break loop when I type 
> in something nonsensical - I just want it to describe the problem and 
> return to top-level.
> 
> If this cannot be done in ANSI CL, then a means for doing it in clisp 
> would be most helpful.

There's probably a keystroke which allows you to quickly get to the top 
level to make this less painful.

However, here is a function definition that gives you an idea how you 
could approach it, if you really want to. (It's not perfect.)

(defun repl-without-errors ()
   (tagbody
    restart
    (handler-case
        (loop (print '>)
              (print (eval (read))))
      (error (c)
             (print c)
             (go restart)))))

CL-USER 5 > (repl-without-errors)

 > (+ 4 5)
9
 > (foo 8)
#<UNDEFINED-FUNCTION 100AEB37>
 > (* 2 3)
6
 >

Pascal

-- 
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/