Julian, see my other post, it has nothing to do with map per se. Apart from philosophical questions, the reason I need this to consistently raise an exception, is that I want to interrupt the map evaluation when it is slow, throwing an InteruptedException. I then want to recommence evaluation later. rinse, repeat. I can't recommence it if the sequence has been 'closed' with a final nil. Sounds like a fair use case?
On Monday, 3 December 2012 16:35:39 UTC+11, julianrz wrote: > > Hmm.. I think you are raising both a technical and a philosophical issue - > what exactly should a higher-order function return when some application of > the supplied function throws exception... The behaviors could be: > 1) throw > 2) return null > 3) return an empty collection (do not continue after 1st failure) > 4) same, but continue through all failures > 5) return collection with valid applications only > What is good behavior? We should have as little uncertainly as possible... > I have to admit my first thought is 'just don't allow it to throw, return > null instead'. This would allow to still collect results (where it does not > throw), and they will be at the matching index locations... > > Now the technicality. The map code I see for 1.4 is trying to append > result of all invocations to a buffer upfront. And each time it will fail, > and the buffer will be empty, hence empty result Source is a chunked > collection and there is only one chunk, it will be done immediately, and > not on subsequent calls - laziness has not started yet > > Please contrast it with mapv, which results in a vector, not sequence > user=> (def mapped (mapv (fn [_] (throw (Exception.))) [1 2 3])) > Exception user/fn--1 (NO_SOURCE_FILE:1) > user=> mapped > #<Unbound Unbound: #'user/mapped> > > Now the lazy-seq example - maybe the difference in behavior can be > explained by the fact that lazy-seq caches the result of body evaluation > and will keep returning it. Since there is an exception during each > evaluation, the caching does not quite happen, and it is re-evaluated? > > Should the behavior be the same in all 3 cases? I think so, at least for > consistency (unsure it can be achieved, though). But throwing in function > passed to map really is something you should not do, and I would recommend > to change map function to return a null or throw -- to let you know that > your code can cause odd behavior. BTW I am not aware of any clojure book > that alerts you to that. > > Also, maybe the implementation of map function should catch your exception > internally and produce a null, and return a sequence of nulls? > > -Julian > > On Sunday, December 2, 2012 5:58:08 AM UTC-8, Hank wrote: >> >> I'm mapping a function that throws an exception over a collection: >> >> => (def mapped (map (fn [_] (throw (Exception.))) [1 2 3])) >> #'user/mapped >> >> 'map' is lazy so we're not expecting to see the exception until we're >> trying to access the result: >> => mapped >> Exception user/fn--709 (NO_SOURCE_FILE:1) >> >> All good, let's do that again: >> => mapped >> () >> >> Whoops! Is this by design? Why? Where does that empty sequence come from? >> >> 'map' is really just calling the lazy-seq macro but doing this with lazy >> seq works just fine: >> => (def lazy (lazy-seq (throw (Exception.)))) >> #'user/lazy >> => lazy >> Exception user/fn--733 (NO_SOURCE_FILE:1) >> => lazy >> Exception user/fn--733 (NO_SOURCE_FILE:1) >> >> Same exception over and over again as it should be. I stared at the >> implementations of 'map' and lazy-seq/LazySeq for some hours but I really >> can't see it. >> >> Cheers >> -- hank >> >> -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en