Incidentally, sorry for the mangled formatting / narrow margins that my emails keep having. I'm not doing that, it's coming from GMail.
On Tue, May 15, 2018 at 10:06 AM, David Storrs <[email protected]> wrote: > On Tue, May 15, 2018 at 1:28 AM, Matthew Butterick <[email protected]> wrote: >> To add to your pile of options, because you said "certain error conditions": >> perhaps you might `raise` an exception in the db code that gets caught by >> the network code (using `with-handlers`). In this way the dependency only >> runs one direction (network module imports db module) but the db module can >> still propagate messages to the network module (by going "backward" through >> the existing calling chain with an exception, rather than "forward" by >> calling into the db module). >> >> Here is a toy example of a `db` module that keeps kicking back an exception >> to a `network` module until it gets zero, no circularity needed: >> >> #lang racket >> >> (module db racket >> (provide f) >> (define (f val) >> (if (zero? val) >> 'finally-a-zero! >> (raise val)))) >> >> (module network racket >> (require (submod ".." db)) >> (let loop ([maybe-err-int #f]) >> (with-handlers ([integer? loop]) >> (when maybe-err-int >> (displayln (number->string maybe-err-int))) >> (f (random 10))))) >> >> (require 'network) > > Brilliant! That's perfect, thank you. > > On that subject, I note the existence of handy/try on the package > server. It provides a macro for exception handling that combines > 'with-handlers' and 'dynamic-wind' while having better end weight than > the former. It comes in several flavors, the most general of them > being: > > (try [(do database thing here) (write files to disk)] > [pre (mark records in DB as locked and lock files on disk before > the main body of the try runs)] > [catch (exn:fail:db (lambda (e) (displayln (~a "Database failed > with message: " (exn-message e))))) > (exn:fail:filesystem (lambda (e) (displayln (~a > "failed to write file: " (exn-message e)))))] > [finally (unlock records in DB, unlock files)]) > > This reduces to: > > (with-handlers ([(exn:fail:db (lambda (e) (displayln (~a "Database > failed with message: " (exn-message e)))))] > [(exn:fail:filesystem (lambda (e) (displayln > (~a "failed to write file: " (exn-message e)))))]) > (dynamic-wind > (thunk (mark records in DB as locked and lock files on disk > before the main body of the try runs)) > (thunk (do database thing here) (write files to disk)) > (thunk (unlock records in DB, unlock files)))) > > I believe the 'try' version to be better because it is syntactically > simpler, explicitly labels the different parts of the 'dynamic-wind' > instead of requiring that you know what they are, and provides better > end weight in the 'with-handlers' -- the body of the code is up front > so you know what is supposed to happen, while the error handling / > preflight / cleanup are tucked away at the end so that you already > know the context and don't need to think about them while dealing with > the happy path. > > The 'pre', 'catch', and 'finally' blocks are all optional and leaving > them out simply defatalizes and returns the exception if there is one. > I should create a version that lets you put 'pre' ahead of the body if > that's what you want, but I haven't done that yet. > > >> >> >> On May 14, 2018, at 10:28 AM, David Storrs <[email protected]> wrote: >> >> This worked fine until now, but I've gotten to a point where they're >> circular -- the network code needs to receive the chunk and then >> forward it to the DB code, but if certain error conditions come up >> then the DB code needs to tell the network code to re-request the >> data. >> >> There's various ways I could work around this (simplest being to put >> all the functions in one file), but I'm wondering if there's a >> recommended way? C would solve this with a .h file. Perl would solve >> it with function prototypes (or simply be able to sort it out without >> intervention). What is the preferred Racket way, or am I simply not >> thinking about it correctly? >> >> -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.

