motivation behind laziness of apply in ClojureScript
When trawling the ClojureScript source, I was a little puzzled when I first noticed that cljs.core/apply respects the laziness of the seq its provided. Fogus mentioned this feature in his Clojure/west talk and it reminded me of my earlier puzzlement. This choice seems to contradict Clojure's eager argument evaluation semantics. Is the motivation of this choice described anywhere? I'm guessing I am missing an obvious use case. -- 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
Re: motivation behind laziness of apply in ClojureScript
On Mar 27, 11:51 pm, Nathan Sorenson n...@sfu.ca wrote: When trawling the ClojureScript source, I was a little puzzled when I first noticed that cljs.core/apply respects the laziness of the seq its provided. Fogus mentioned this feature in his Clojure/west talk and it reminded me of my earlier puzzlement. This choice seems to contradict Clojure's eager argument evaluation semantics. Is the motivation of this choice described anywhere? I'm guessing I am missing an obvious use case. You've misunderstood how clojure.core/apply behaves - it passes sequences lazily as well. For example, (apply (fn f [ args] (take 3 args)) (range)) works fine, even though you pass an infinite number of arguments to f. -- 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
Re: motivation behind laziness of apply in ClojureScript
Your right the core apply is lazy too. The same question still remains: is there a use case behind apply being lazy when Clojure is otherwise a strictly evaluating language? Perhaps is this the intended mechanism to smuggle non-strictness into evaluation? -- 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
Re: motivation behind laziness of apply in ClojureScript
Actually now that I've thought about it, you couldn't mimic non-strict evaluation with lazy apply, so that's not a use-case. All you could provide is left-to-right argument non-strictness which is not sufficient. W.r.t. your example, you can force evaluation the first 3 args, but you can't, say, force the evaluation of only the 3rd argument like in Haskell. I use apply to leverage list processing functions to massage input to functions that are generally non-seq-ey. If a function is intended to operate on lazy sequences, it seems to me that you would pass those sequences in as explicit arguments, in the same manner as all the Clojure seq operations. Again, we don't have the machinery to mimic non-strict evaluation so I don't think building functions that behave in this halfways-non-strict manner is obvious design. I'd like to see a function that depends on the left-to-right-non-strictness that lazy apply provides. -- 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
Re: motivation behind laziness of apply in ClojureScript
is there a use case behind apply being lazy when Clojure is otherwise a strictly evaluating language In clojure-py we have to pass vararg arguments as tuples. So it ends up a lot like (to-tuple (concat args seqarg)) I always saw the seq argument in IFn as a crutch to get around the we have too many vars to pass to this function problem. Basically, since the JVM doesn't support lazy varargs, Clojure doesn't either. Timothy -- 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
Re: motivation behind laziness of apply in ClojureScript
On Wed, Mar 28, 2012 at 2:13 PM, Timothy Baldridge tbaldri...@gmail.com wrote: is there a use case behind apply being lazy when Clojure is otherwise a strictly evaluating language In clojure-py we have to pass vararg arguments as tuples. So it ends up a lot like (to-tuple (concat args seqarg)) I always saw the seq argument in IFn as a crutch to get around the we have too many vars to pass to this function problem. Basically, since the JVM doesn't support lazy varargs, Clojure doesn't either. Apply isn't really non-strict. If your source contains (apply foo x y z w) then apply, foo, x, y, z, and w will all be evaluated, in left-to-right order, before foo is called with x, y, z, and the contents of w as arguments. If w is a literal such as [w1 w2 w3 w4] then w1, w2, w3, and w4 will get evaluated, after z and in left-to-right order, before foo is called. In other words, any side effects in a line like (apply foo x y z [w1 w2 w3 w4]) happen in the order one would expect. And if w is really a lazy sequence, and a lambda involved in generating it has side effects, the fact that the side effects are in a lambda (or not even in the (apply...) line) tells you that the side effects may be delayed. Further, it's possible to get a kind of non-strict-analogous behavior (side effects may be delayed, reordered, or not happen at all) in Clojure if foo and its caller are written specially. For example, (defn weird-and [x y] (if @x @y)) (weird-and (delay (long-running-test-1)) (delay (long-running-test-2))) will only compute the second expensive test if the first didn't return logical false. (The built-in and macro also short-circuits, but does so by being a macro. Unlike and, weird-and could be passed to a HOF. But the HOF would have to know to pass it delays rather than normal booleans. You could do (reduce weird-and [(delay this) (delay that) ...]).) -- 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
Re: motivation behind laziness of apply in ClojureScript
May be delayed But I don't think they ever are: user= (def oddseq (map #(do (print %) %) (range 30))) #'user/oddseq user= (defn foo [ args] 'd) #'user/foo user= (apply foo oddseq) 01234567891011121314151617181920212223242526272829d user= (def oddseq (map #(do (print %) %) (range 1))) #'user/oddseq user= (apply foo oddseq) 0d user= I don't think it's possible to ever have apply not evaluate all its arguments? I think this is what Nathan was saying. Given the above example, is there anyway to not have the side effects automatically run when invoking apply? Timothy -- “One of the main causes of the fall of the Roman Empire was that–lacking zero–they had no way to indicate successful termination of their C programs.” (Robert Firth) -- 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
Re: motivation behind laziness of apply in ClojureScript
I don't think it's possible to ever have apply not evaluate all its arguments? I think this is what Nathan was saying. Cedric is right that apply, itself, is strict and evaluates its arguments as one might expect. But I'm not referring to manual thunking/delaying your arguments to mimic laziness in a strict language. What I'm trying to understand is that one is able to write a polyvariadic function that *doesn't* completely realize the rest parameter (but only in the case that the fn is invoked via apply with a lazy seq argument). It's this combination of requirements that means apply should *not* construct a tuple (as in clojure-py) or cons arguments together into a list (as I'm currently doing in clojure-scheme) as these operations will cause the realization of the entire applied sequence. Given the above example, is there anyway to not have the side effects automatically run when invoking apply? Yes. If you bury an effect into the lazy-seq at some position n, it won't be realized unless the applied function is either fixed-arity up to n, or chooses to force the lazy-seq up to n (modulo chunked evaluation). My question is what would require this sort of function? Is there a use-case for a function that expects to be called via 'apply' to avoid evaluating some of its arguments? (Again, this isn't a question of thunking; The user of this hypothetical function can apply it with a strict list or a lazy list and no code needs to change--I, as a caller, don't need to explicitly thunk arguments for laziness and the fn doesn't need to explicitly force/dereference them). Put another way: why does apply need to promise not to realize its seq argument? -- 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
Re: motivation behind laziness of apply in ClojureScript
An example of lazy apply, with your foo fn: (apply foo (iterate inc 0)) d -- 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
Re: motivation behind laziness of apply in ClojureScript
On Wed, Mar 28, 2012 at 8:32 PM, Nathan Sorenson n...@sfu.ca wrote: I don't think it's possible to ever have apply not evaluate all its arguments? I think this is what Nathan was saying. Cedric is right that apply, itself, is strict and evaluates its arguments as one might expect. But I'm not referring to manual thunking/delaying your arguments to mimic laziness in a strict language. What I'm trying to understand is that one is able to write a polyvariadic function that *doesn't* completely realize the rest parameter (but only in the case that the fn is invoked via apply with a lazy seq argument). It's this combination of requirements that means apply should *not* construct a tuple (as in clojure-py) or cons arguments together into a list (as I'm currently doing in clojure-scheme) as these operations will cause the realization of the entire applied sequence. I suggest that apply should, if the function has no rest argument, realize enough of its input(s) to either be ready to call the function or know there's at least one more argument than the function's highest arity and throw an exception; if the function has a rest argument, it should cons up a list of arguments until either it runs out or there's enough for all the non-rest arguments of the highest arity overload, then call the function (or throw) if it's exhausted its input or else call the function with the rest argument bound to the unrealized tail of the input. So, if the input is (range), then: for (defn foo [a b]) it would realize 0, 1, and 2, then throw arity. for (defn foo [a b r]) it would realize 0 and 1, then call foo with (nth (range) 0) (nth (range) 1) (next (next (range))) as a, b, and r. My question is what would require this sort of function? Is there a use-case for a function that expects to be called via 'apply' to avoid evaluating some of its arguments? I can't think of any offhand. Put another way: why does apply need to promise not to realize its seq argument? (apply + some-lazy-seq-too-big-to-fit-in-main-memory) Not avoid evaluating some of its arguments but avoid holding onto the head in that case. -- 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
Re: motivation behind laziness of apply in ClojureScript
On Wed, Mar 28, 2012 at 7:16 PM, Timothy Baldridge tbaldri...@gmail.com wrote: May be delayed But I don't think they ever are: user= (def oddseq (map #(do (print %) %) (range 30))) #'user/oddseq user= (defn foo [ args] 'd) #'user/foo user= (apply foo oddseq) 01234567891011121314151617181920212223242526272829d user= (def oddseq (map #(do (print %) %) (range 1))) #'user/oddseq user= (apply foo oddseq) 0d user= I don't think it's possible to ever have apply not evaluate all its arguments? I think this is what Nathan was saying. Given the above example, is there anyway to not have the side effects automatically run when invoking apply? Range is chunked, and I think the map-generated sequence inherits that. On the other hand, I thought the chunk size was 16, and that it didn't matter anyway if no element was ever requested. On the gripping hand, (apply f x) calls (seq x), which realizes the first element (and thus the first chunk, for chunked seqs) to determine if x is empty and it should therefore return nil. -- 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
Re: motivation behind laziness of apply in ClojureScript
Put another way: why does apply need to promise not to realize its seq argument? (apply + some-lazy-seq-too-big-to-fit-in-main-memory) Not avoid evaluating some of its arguments but avoid holding onto the head in that case. I'd reach for 'reduce' in this case but that's still a valid point. -- 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