openlang

Returning from a Common Lisp handler means declining

Neat abbreviation. I'd still like to see what it's agreeing to.

The wrapper macro installs a handler around a parser, and the parser signals a condition when a field is missing. The handler writes a note and returns normally. In Common Lisp that normal return means the handler declined. It says nothing about the parser having recovered, and signaling doesn't have to unwind anything right away.

Now swap that handler for one the caller passes in. It might decline, transfer control, or invoke whatever restart is available. Trace one signal through both versions before trusting how tidy the wrapper looks.

So what does the macro actually promise? Who establishes the restarts, how long do they stay available, and what can the parser assume when signaling returns? A short spelling is nice for recognizing the protocol, but the agreement itself should be written down somewhere other than the expansion.

后续讨论 4

顺着彼此的依据读下去
  1. 固定链接

    For each restart, which action does it permit, and which caller knows enough to pick it? The Java comparison is useful here. A checked declaration puts a compile-time obligation on the caller and still doesn't list every failure that can happen at run time.

  2. 固定链接

    Keep the logging handler as everyone's first guess. Then change only what it does, so it invokes a restart that supplies a value. If the wrapper calls both of those "handled", the example has found the missing distinction for you.

    Those two traces could sit right next to the macro, with where execution resumes in each. Read that way, the abbreviation might be easier than expanding it every time, as long as the docs also cover a handler that declines.

  3. 固定链接

    Scheme splits this question into two procedures, which helps a wrapper say what it means. In R7RS, if a handler installed with with-exception-handler returns from a raise, a secondary exception is raised in the dynamic environment of the handler. With raise-continuable, the handler's return value becomes the value of the call and the parser carries on. So "the handler returned" has two different meanings depending on which one the parser used, and the macro's documentation should name which. Section 6.11 is short and worth reading whole.

  4. 固定链接

    The first thing to pin down is which function the parser uses to signal, because that fixes what a declining handler leaves behind.

    With signal, every handler can decline and the call simply returns nil. The parser then continues with a missing field, and its own code has to say what happens next. With error, a normal return is impossible. If no handler transfers control, invoke-debugger runs. With cerror, a continue restart is available while the condition is signaled, and a handler that invokes it makes cerror return nil.

    So the logging handler from the root means three different things. Under signal the parse goes on with a hole in it. Under error the note is written and the debugger comes up anyway. Under cerror the note is written and the debugger comes up unless some outer handler picks continue. The macro's documentation should name the function and state what the parser assumes after a return from it.

同一个问题的其他角度

  1. foldl composes fine and leaks anyway

    foldl (+) 0 over a long list is the smallest space leak I know, and it's a composition problem more than an arithmetic one. E…

    回复 6最近活动 haskell
  2. Empty reductions return the identity

    Reduce over an empty vector. APL answers. Each primitive carries its identity. Zero for plus. One for times and for and. ⌈/⍬…

    回复 3最近活动 apl
  3. age>=18=>allow and the Racket reader

    Rule authors want to write age>=18=>allow, no spaces, no parentheses. Racket's default reader may hand that over as one symbo…

    回复 8最近活动 racket