[racket] Handling errors from in-directory - and handling errors more generally

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Tue Oct 12 13:57:08 EDT 2010

Peter could roll his own in-directory recursive function in just a few line catching the relevant exceptions: 

> (define (traverse d)
>   (parameterize ([current-directory d])
>     (define d (directory-list))
>     (for-each (lambda (x)
>                 (printf "~a " x)
>                 (define p (with-handlers ([exn:fail:filesystem? void])
>                             (file-or-directory-permissions x)))
>                 (displayln p)
>                 (define n (build-path x))
>                 (when (and (directory-exists? n) (memq 'read p))
>                   (traverse (build-path x))))
>               d)))

-- Matthias

On Oct 12, 2010, at 11:50 AM, Matthew Flatt wrote:

> At Tue, 12 Oct 2010 14:48:49 +0100, Peter Kiggins wrote:
>> [I am completely new to both Scheme and racket, so if my questions are
>> Looking at traversal of a file tree led me to in-directory.  The
>> problem is that as soon as it hits a directory it cannot search
>> (permissions, whatever...) it drops out with an exception.  For
>> example:
>> (for ([e (in-directory "/Users/lucas")])
>>   (printf "~a\n" e))
>> /Users/lucas/.CFUserTextEncoding
>> /Users/lucas/.DS_Store
>> /Users/lucas/Desktop
>> directory-list: could not open "/Users/lucas/Desktop" (Permission
>> denied; errno=13)
>> I'd like to be able to catch the error, change the output, and
>> continue pulling names:
>> (for ([e (safe-in-directory "/Users/lucas")])
>>   (printf "~a\n" e))
>> /Users/lucas/.CFUserTextEncoding
>> /Users/lucas/.DS_Store
>> /Users/lucas/Desktop[permission denied]
>> /Users/lucas/morefiles
>> ...
>> ...
>> How is in-directory meant to be used, so that it re-starts after an
>> error? 
> I don't think there's a way currently to have `in-directory' continue
> at that point.
>> In general, what is idiomatic for catching exceptions, re-trying after
>> an exception, running finalise code?  Is there an equivalent to Clisp
>> restarts?
> No particular restart system built into the exception system. Code that
> raises an exception can include a continuation in the exception to
> allow a restart, and the exception raised for an asynchronous break
> (which is usually triggered when you hit Ctl-C) does that. But
> `directory-list' as used by `in-directory' doesn't include a restart
> continuation in the exception record that it creates, and
> `in-directory' doesn't particularly catch exceptions or introduce any
> restart continuations.
> Among Racket procedures that support specific failure handling, most do
> so through an optional failure-thunk argument. For example, `hash-ref'
> and `file-or-directory-modify-seconds' accept failure thunks. The
> handlers in those cases just produce an alternate result --- the same
> thing could be accomplished by catching an exception --- as opposed to
> continuing internally. So, I think there's not really much precedent
> for this in the Racket API.
> _________________________________________________
>  For list-related administrative tasks:
>  http://lists.racket-lang.org/listinfo/users

Posted on the users mailing list.