公共lisp重新启动条件绑定 [英] Common lisp restart to condition binding

查看:153
本文介绍了公共lisp重新启动条件绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在空闲时间里正在学习普通的lisp,并且有关于条件系统的问题。



当我们处理公共lisp中的错误时,我们在处理程序中指定了错误类型,以确定要处理的错误。在提升和处理错误之间,我可以放置一些重新启动(例如重新启动大小写),但是我不能在重新启动时指定错误类型。



例如,假设我有一个接收字符串和流的函数,将字符串发送到流,并从流中读取响应并返回。假设如果我的消息错误,我从流中读取错误响应。我想提出一个错误并绑定一个重新启动,要求新的消息,如下所示:

 (defun process-message(stream原始消息)
(let((response(get-response stream raw-message)))
(restart-case
(when(response-error-p response))
(错误'message-error:文本响应))
(change-raw-message(msg)
(进程消息流msg)))))

现在假设消息很复杂,我在另一个更高级别的另一个功能 send-command 可以从一些参数创建一个消息并调用进程消息。我想绑定另一个重新启动 recreate-command-message ,这将允许用户从参数发送新的命令,如果'message-error 获取。这个重新启动可能是重新启动的地方,在进程消息中,但是它不完全正确,因为进程消息不应该知道这样的高级功能,如 send-command ,返回值可能不同。



但是现在,流错误(如EOF等)将被抛出 recreate-command-message 如果套接字将失败,则在某些超级高级套接字错误中可以使用 rebuate-command-message 处理程序和这个重新启动将是无用的,惯用的错误。



这是一个程序设计问题,一个程序应该设计为避免这样的问题,或者我只是找不到如何绑定重新启动到错误类型或我不明白条件系统正确?



谢谢。

解决方案

也许这有助于:

 (define-condition low-level-error(simple-error)
()
(:report(lambda(cs)
(format slow level error。))))

(define-condition high-level-错误(简单错误)
()
(:report(lambda(cs)
(格式为高级错误))))

defun低级(erro rp)
(重新启动案例
(当errorp(错误'低级错误))
(go-on()
:报告从低级别
t)))

(defun高级别(高级错误-p低级错误-p)
(重新启动案例
( progn
(当高级错误-p(错误'高级错误))
(低级别低级错误-p))
(go-on( )
:报告从高级别
:test(lambda(c)(typep c'high-level-error))
t))

尝试使用不同的值调用高级 t nil ),并检查相应的可用重新启动是否符合您的需求。只有在发出高电平的错误信号时才会看到高电平的重新启动,而由于较高级别的重新启动被保持在堆栈中,所以较低级别的功能将不必了解高级别的恢复方式。



对于您的特定用例,如果我理解正确,这意味着:建立您的 rebuate-command-message restart在 send-command 中重新调用进程消息,并使其仅适用于高级错误。 p>

正如你在阅读PCL章节Vsevolod之后所知道的那样,实际上处理这些错误,即决定要调用哪些重新启动,使用 handler-bind handler-case


I'm learning common lisp in my free time and have a questions about the condition system.

When we handle an error in common lisp we specify error-type in a handler to determine which error to handle. Between raising and handling an error I can place some restarts (for example with restart-case) but I cannot specify in restart an error type.

For example, assume I have a function that takes a string and a stream, sends string to stream and read the response from stream and returns it. Assume that if my message is wrong I read from stream an error response. And I want to raise an error and bind a restart that asks for new message like this:

(defun process-message (stream raw-message)
  (let ((response (get-response stream raw-message)))
    (restart-case
        (when (response-error-p response)
          (error 'message-error :text response))
      (change-raw-message (msg)
        (process-message stream msg)))))

Now assume that the message is complicated and I got another function send-command at higher level that can create a message from some arguments and calls the process-message. I want to bind another restart recreate-command-message that will allow user to send new command from arguments if 'message-error acquires. This restart could be places in restart-case at process-message, but it is not fully correct because process-message should not know about such high-level function like send-command and the return values can differ.

But now the stream errors (such as EOF etc.) will be thrown throw recreate-command-message and if socket will fail the recreate-command-message restart will be available in some super-high-level socket-error handler and this restart will be useless and idiomatically wrong.

Is this a program design problem and a program should be designed to avoid such problems, or I just cannot find how to bind restart to error type or I do not understand the condition system correctly?

Thanks.

解决方案

Maybe this helps:

(define-condition low-level-error (simple-error)
  ()
  (:report (lambda (c s)
             (format s "low level error."))))

(define-condition high-level-error (simple-error)
  ()
  (:report (lambda (c s)
             (format s "high level error."))))

(defun low-level (errorp)
  (restart-case
      (when errorp (error 'low-level-error))
    (go-on ()
      :report "go on from low-level"
      t)))

(defun high-level (high-level-error-p low-level-error-p)
  (restart-case
      (progn
        (when high-level-error-p (error 'high-level-error))
        (low-level low-level-error-p))
    (go-on ()
      :report "go on from high level"
      :test (lambda (c) (typep c 'high-level-error))
      t)))

Try invoking high-level with different values (t or nil) for its arguments and check in the debugger if the respective available restarts fit your needs. The high level restart will only be seen if a high level error is signalled, and since the restart for the higher level is kept up the stack, the lower level function won't have to know about high level means to recover.

For your particular use-case, if I understand you correctly, this would mean: Establish your recreate-command-message restart to re-invoke process-message in send-command, and make it only available for high level errors.

As you probably know after reading the PCL chapter Vsevolod linked above, actually handling those errors, i.e. deciding which restarts to invoke, is done with handler-bind and handler-case.

这篇关于公共lisp重新启动条件绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆