Re: Lazy Flatten; One seq at a Time

2017-11-24 Thread Ray Miller
If I've understood your problem correctly, clojure.core/lazy-cat does
exactly what you need.

Ray.

On 22 November 2017 at 22:31, Stephen Nelson <step...@montoux.com> wrote:

> ```
> (->> (repeatedly
>(fn []
>  (lazy-seq
>(println "New seq...")
>(map (fn [x] + x (rand-int 10)) (range 4)
>  (apply concat)
>  (take 1))
> New seq...
> => (3)
> ```
>
> Lazy-flatten is unnecessary because concat already does what you want –
> the generalised problem you're running in to is that function arguments are
> eagerly realised. In your case, your use of concat realises the first two
> seqs, in my example, `apply` realises the first four elements (see the
> implementation of apply).
>
> If you wrap the seq generator in `lazy-seq` you can delay the realisation
> of the 'expensive' inner sequence until concat reaches that list. In
> implementation terms, lazy-seq is a macro returns a thunk that will delay
> the println (and the sequence generation) until it's required by concat.
>
> On Thu, Nov 23, 2017 at 2:32 AM Matt Anderson <manderson...@gmail.com>
> wrote:
>
>> Thanks! The `aconcat` solution from plumbing works great for this use
>> case.
>>
>> The `lazy-gen`/`yield` fn's in Tupelo are exactly what I was searching
>> for in terms of a larger abstraction, but couldn't quite put into words.
>> Thanks for the tip!
>>
>>
>>
>> On Wednesday, November 22, 2017 at 2:36:18 AM UTC-5, Alan Thompson wrote:
>>
>>> You can also solve this using `lazy-gen` and `yield-all` from the
>>> Tupelo library
>>> <https://github.com/cloojure/tupelo#generator-functions-for-lazy-sequences-a-la-python>.
>>> It allows you to make
>>> a lazy generator function (a la Python):
>>>
>>>   (let [seq-of-seqs [(range  0  5)
>>>  (range 10 15)
>>>  (range 20 25)]
>>> flat-seq(lazy-gen
>>>   (doseq [curr-seq seq-of-seqs]
>>> (yield-all curr-seq)))]
>>> (is= flat-seq [0 1 2 3 4 10 11 12 13 14 20 21 22 23 24]))
>>>
>>>
>>> Alan
>>>
>>> On Tue, Nov 21, 2017 at 4:47 PM, Jason Wolfe <ja...@w01fe.com> wrote:
>>>
>> I think this
>>>> <https://github.com/plumatic/plumbing/blob/318af7798bb701607aaae8639d12829014941184/src/plumbing/core.cljx#L182>
>>>> will do it:
>>>>
>>>> (lazy-cat (first coll) (when-let [n (next coll)] (lazy-flatten n
>>>>
>>>>
>>>> On Tuesday, November 21, 2017 at 2:34:15 PM UTC-8, Matt Anderson wrote:
>>>>>
>>>>> I have a function that is returning a lazy-seq of lazy-seq's.
>>>>>
>>>>>
>>>>> (seq (seq [1 2 3]) (seq [4 5 6]) ...)
>>>>>
>>>>>
>>>>> The end-user API, however, should be able to get back a lazy-seq of
>>>>> the individual items across all lazy-seq's--essentially a flattening of 
>>>>> the
>>>>> output of my function--instead of the "top level" seqs.
>>>>>
>>>>>
>>>>> (seq [1 2 3 4 5 6 ...])
>>>>>
>>>>> Each of the internal lazy-seq's is expensive in terms of memory usage
>>>>> so I'd like to only "load" one at a time.  I've been trying to find a way
>>>>> to only calculate one of the top-level lazy-seq's at a time and then not
>>>>> "take" the next until the user gets to the end of the first and needs the
>>>>> first item from the next (eg: (seq [4 5 6]) doesn't get calculated until 
>>>>> we
>>>>> have consumed 3 and are asking for the next), but haven't found a way to 
>>>>> do
>>>>> it. Best I've gotten is "loading" 2 "top level" seqs at a time and I'm
>>>>> afraid that may be the best I get, but I thought it might be an exercise
>>>>> worth presenting in case anyone had ideas. Here's a contrived example:
>>>>>
>>>>>
>>>>> (defn lazy-flatten
>>>>>
>>>>>  [coll]
>>>>>
>>>>>  (when-let [s (seq coll)]
>>>>>
>>>>>(lazy-seq
>>>>>
>>>>>  (if (seq? (first s))
>>>>>
>>>>>(concat (lazy-flatten (first s)) (lazy-flatten (rest s)))
>>>>>
>>>>>(cons (first s) (lazy

Re: Lazy Flatten; One seq at a Time

2017-11-22 Thread Stephen Nelson
```
(->> (repeatedly
   (fn []
 (lazy-seq
   (println "New seq...")
   (map (fn [x] + x (rand-int 10)) (range 4)
 (apply concat)
 (take 1))
New seq...
=> (3)
```

Lazy-flatten is unnecessary because concat already does what you want – the
generalised problem you're running in to is that function arguments are
eagerly realised. In your case, your use of concat realises the first two
seqs, in my example, `apply` realises the first four elements (see the
implementation of apply).

If you wrap the seq generator in `lazy-seq` you can delay the realisation
of the 'expensive' inner sequence until concat reaches that list. In
implementation terms, lazy-seq is a macro returns a thunk that will delay
the println (and the sequence generation) until it's required by concat.

On Thu, Nov 23, 2017 at 2:32 AM Matt Anderson <manderson...@gmail.com>
wrote:

> Thanks! The `aconcat` solution from plumbing works great for this use case.
>
> The `lazy-gen`/`yield` fn's in Tupelo are exactly what I was searching for
> in terms of a larger abstraction, but couldn't quite put into words. Thanks
> for the tip!
>
>
>
> On Wednesday, November 22, 2017 at 2:36:18 AM UTC-5, Alan Thompson wrote:
>
>> You can also solve this using `lazy-gen` and `yield-all` from the Tupelo
>> library
>> <https://github.com/cloojure/tupelo#generator-functions-for-lazy-sequences-a-la-python>.
>> It allows you to make
>> a lazy generator function (a la Python):
>>
>>   (let [seq-of-seqs [(range  0  5)
>>  (range 10 15)
>>  (range 20 25)]
>> flat-seq(lazy-gen
>>   (doseq [curr-seq seq-of-seqs]
>> (yield-all curr-seq)))]
>> (is= flat-seq [0 1 2 3 4 10 11 12 13 14 20 21 22 23 24]))
>>
>>
>> Alan
>>
>> On Tue, Nov 21, 2017 at 4:47 PM, Jason Wolfe <ja...@w01fe.com> wrote:
>>
> I think this
>>> <https://github.com/plumatic/plumbing/blob/318af7798bb701607aaae8639d12829014941184/src/plumbing/core.cljx#L182>
>>> will do it:
>>>
>>> (lazy-cat (first coll) (when-let [n (next coll)] (lazy-flatten n
>>>
>>>
>>> On Tuesday, November 21, 2017 at 2:34:15 PM UTC-8, Matt Anderson wrote:
>>>>
>>>> I have a function that is returning a lazy-seq of lazy-seq's.
>>>>
>>>>
>>>> (seq (seq [1 2 3]) (seq [4 5 6]) ...)
>>>>
>>>>
>>>> The end-user API, however, should be able to get back a lazy-seq of the
>>>> individual items across all lazy-seq's--essentially a flattening of the
>>>> output of my function--instead of the "top level" seqs.
>>>>
>>>>
>>>> (seq [1 2 3 4 5 6 ...])
>>>>
>>>> Each of the internal lazy-seq's is expensive in terms of memory usage
>>>> so I'd like to only "load" one at a time.  I've been trying to find a way
>>>> to only calculate one of the top-level lazy-seq's at a time and then not
>>>> "take" the next until the user gets to the end of the first and needs the
>>>> first item from the next (eg: (seq [4 5 6]) doesn't get calculated until we
>>>> have consumed 3 and are asking for the next), but haven't found a way to do
>>>> it. Best I've gotten is "loading" 2 "top level" seqs at a time and I'm
>>>> afraid that may be the best I get, but I thought it might be an exercise
>>>> worth presenting in case anyone had ideas. Here's a contrived example:
>>>>
>>>>
>>>> (defn lazy-flatten
>>>>
>>>>  [coll]
>>>>
>>>>  (when-let [s (seq coll)]
>>>>
>>>>(lazy-seq
>>>>
>>>>  (if (seq? (first s))
>>>>
>>>>(concat (lazy-flatten (first s)) (lazy-flatten (rest s)))
>>>>
>>>>(cons (first s) (lazy-flatten (rest s)))
>>>>
>>>> (->> (repeatedly
>>>>(fn []
>>>>  (println "New seq...")
>>>>  (map (fn [x] + x (rand-int 10)) (range 4
>>>>  lazy-flatten
>>>>  (take 1))
>>>>
>>>>
>>>>
>>>> Prints:
>>>>
>>>>
>>>> New seq...
>>>>
>>>> New seq...
>>>>
>>>> => (8)
>>>>
>>>>
>>>> I realize this is because 2 items must be taken for "concat", so there
>>

Re: Lazy Flatten; One seq at a Time

2017-11-22 Thread Matt Anderson
Thanks! The `aconcat` solution from plumbing works great for this use case.

The `lazy-gen`/`yield` fn's in Tupelo are exactly what I was searching for 
in terms of a larger abstraction, but couldn't quite put into words. Thanks 
for the tip!



On Wednesday, November 22, 2017 at 2:36:18 AM UTC-5, Alan Thompson wrote:
>
> You can also solve this using `lazy-gen` and `yield-all` from the Tupelo 
> library 
> <https://github.com/cloojure/tupelo#generator-functions-for-lazy-sequences-a-la-python>.
>  
> It allows you to make
> a lazy generator function (a la Python):
>
>   (let [seq-of-seqs [(range  0  5)
>  (range 10 15)
>  (range 20 25)]
> flat-seq(lazy-gen
>   (doseq [curr-seq seq-of-seqs]
> (yield-all curr-seq)))]
> (is= flat-seq [0 1 2 3 4 10 11 12 13 14 20 21 22 23 24]))
>
>
> Alan
>
>
> On Tue, Nov 21, 2017 at 4:47 PM, Jason Wolfe <ja...@w01fe.com 
> > wrote:
>
>> I think this 
>> <https://github.com/plumatic/plumbing/blob/318af7798bb701607aaae8639d12829014941184/src/plumbing/core.cljx#L182>
>>  
>> will do it: 
>>
>> (lazy-cat (first coll) (when-let [n (next coll)] (lazy-flatten n
>>
>>
>> On Tuesday, November 21, 2017 at 2:34:15 PM UTC-8, Matt Anderson wrote:
>>>
>>> I have a function that is returning a lazy-seq of lazy-seq's.
>>>
>>>
>>> (seq (seq [1 2 3]) (seq [4 5 6]) ...)
>>>
>>>
>>> The end-user API, however, should be able to get back a lazy-seq of the 
>>> individual items across all lazy-seq's--essentially a flattening of the 
>>> output of my function--instead of the "top level" seqs. 
>>>
>>>
>>> (seq [1 2 3 4 5 6 ...])
>>>
>>> Each of the internal lazy-seq's is expensive in terms of memory usage so 
>>> I'd like to only "load" one at a time.  I've been trying to find a way to 
>>> only calculate one of the top-level lazy-seq's at a time and then not 
>>> "take" the next until the user gets to the end of the first and needs the 
>>> first item from the next (eg: (seq [4 5 6]) doesn't get calculated until we 
>>> have consumed 3 and are asking for the next), but haven't found a way to do 
>>> it. Best I've gotten is "loading" 2 "top level" seqs at a time and I'm 
>>> afraid that may be the best I get, but I thought it might be an exercise 
>>> worth presenting in case anyone had ideas. Here's a contrived example:
>>>
>>>
>>> (defn lazy-flatten
>>>
>>>  [coll]
>>>
>>>  (when-let [s (seq coll)]
>>>
>>>(lazy-seq
>>>
>>>  (if (seq? (first s))
>>>
>>>(concat (lazy-flatten (first s)) (lazy-flatten (rest s)))
>>>
>>>(cons (first s) (lazy-flatten (rest s)))
>>>
>>> (->> (repeatedly
>>>(fn []
>>>  (println "New seq...")
>>>  (map (fn [x] + x (rand-int 10)) (range 4
>>>  lazy-flatten
>>>  (take 1))
>>>
>>>
>>>
>>> Prints:
>>>
>>>
>>> New seq...
>>>
>>> New seq...
>>>
>>> => (8)
>>>
>>>
>>> I realize this is because 2 items must be taken for "concat", so there 
>>> would need to be another approach (this was just my best shot 
>>> implementation). 
>>>
>>>
>>> Any ideas on how to get the bottom form to only print 1 "New seq..."?
>>>
>> -- 
>> You received this message because you are subscribed to the Google
>> Groups "Clojure" group.
>> To post to this group, send email to clo...@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+u...@googlegroups.com 
>> For more options, visit this group at
>> http://groups.google.com/group/clojure?hl=en
>> --- 
>> You received this message because you are subscribed to the Google Groups 
>> "Clojure" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to clojure+u...@googlegroups.com .
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Lazy Flatten; One seq at a Time

2017-11-21 Thread Alan Thompson
You can also solve this using `lazy-gen` and `yield-all` from the Tupelo
library
<https://github.com/cloojure/tupelo#generator-functions-for-lazy-sequences-a-la-python>.
It allows you to make
a lazy generator function (a la Python):

  (let [seq-of-seqs [(range  0  5)
 (range 10 15)
 (range 20 25)]
flat-seq(lazy-gen
  (doseq [curr-seq seq-of-seqs]
(yield-all curr-seq)))]
(is= flat-seq [0 1 2 3 4 10 11 12 13 14 20 21 22 23 24]))


Alan


On Tue, Nov 21, 2017 at 4:47 PM, Jason Wolfe <ja...@w01fe.com> wrote:

> I think this
> <https://github.com/plumatic/plumbing/blob/318af7798bb701607aaae8639d12829014941184/src/plumbing/core.cljx#L182>
> will do it:
>
> (lazy-cat (first coll) (when-let [n (next coll)] (lazy-flatten n
>
>
> On Tuesday, November 21, 2017 at 2:34:15 PM UTC-8, Matt Anderson wrote:
>>
>> I have a function that is returning a lazy-seq of lazy-seq's.
>>
>>
>> (seq (seq [1 2 3]) (seq [4 5 6]) ...)
>>
>>
>> The end-user API, however, should be able to get back a lazy-seq of the
>> individual items across all lazy-seq's--essentially a flattening of the
>> output of my function--instead of the "top level" seqs.
>>
>>
>> (seq [1 2 3 4 5 6 ...])
>>
>> Each of the internal lazy-seq's is expensive in terms of memory usage so
>> I'd like to only "load" one at a time.  I've been trying to find a way to
>> only calculate one of the top-level lazy-seq's at a time and then not
>> "take" the next until the user gets to the end of the first and needs the
>> first item from the next (eg: (seq [4 5 6]) doesn't get calculated until we
>> have consumed 3 and are asking for the next), but haven't found a way to do
>> it. Best I've gotten is "loading" 2 "top level" seqs at a time and I'm
>> afraid that may be the best I get, but I thought it might be an exercise
>> worth presenting in case anyone had ideas. Here's a contrived example:
>>
>>
>> (defn lazy-flatten
>>
>>  [coll]
>>
>>  (when-let [s (seq coll)]
>>
>>(lazy-seq
>>
>>  (if (seq? (first s))
>>
>>(concat (lazy-flatten (first s)) (lazy-flatten (rest s)))
>>
>>(cons (first s) (lazy-flatten (rest s)))
>>
>> (->> (repeatedly
>>(fn []
>>  (println "New seq...")
>>  (map (fn [x] + x (rand-int 10)) (range 4
>>  lazy-flatten
>>  (take 1))
>>
>>
>>
>> Prints:
>>
>>
>> New seq...
>>
>> New seq...
>>
>> => (8)
>>
>>
>> I realize this is because 2 items must be taken for "concat", so there
>> would need to be another approach (this was just my best shot
>> implementation).
>>
>>
>> Any ideas on how to get the bottom form to only print 1 "New seq..."?
>>
> --
> 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
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Lazy Flatten; One seq at a Time

2017-11-21 Thread Jason Wolfe
I think this 
<https://github.com/plumatic/plumbing/blob/318af7798bb701607aaae8639d12829014941184/src/plumbing/core.cljx#L182>
 
will do it: 

(lazy-cat (first coll) (when-let [n (next coll)] (lazy-flatten n

On Tuesday, November 21, 2017 at 2:34:15 PM UTC-8, Matt Anderson wrote:
>
> I have a function that is returning a lazy-seq of lazy-seq's.
>
>
> (seq (seq [1 2 3]) (seq [4 5 6]) ...)
>
>
> The end-user API, however, should be able to get back a lazy-seq of the 
> individual items across all lazy-seq's--essentially a flattening of the 
> output of my function--instead of the "top level" seqs. 
>
>
> (seq [1 2 3 4 5 6 ...])
>
> Each of the internal lazy-seq's is expensive in terms of memory usage so 
> I'd like to only "load" one at a time.  I've been trying to find a way to 
> only calculate one of the top-level lazy-seq's at a time and then not 
> "take" the next until the user gets to the end of the first and needs the 
> first item from the next (eg: (seq [4 5 6]) doesn't get calculated until we 
> have consumed 3 and are asking for the next), but haven't found a way to do 
> it. Best I've gotten is "loading" 2 "top level" seqs at a time and I'm 
> afraid that may be the best I get, but I thought it might be an exercise 
> worth presenting in case anyone had ideas. Here's a contrived example:
>
>
> (defn lazy-flatten
>
>  [coll]
>
>  (when-let [s (seq coll)]
>
>    (lazy-seq
>
>  (if (seq? (first s))
>
>(concat (lazy-flatten (first s)) (lazy-flatten (rest s)))
>
>(cons (first s) (lazy-flatten (rest s)))
>
> (->> (repeatedly
>(fn []
>  (println "New seq...")
>  (map (fn [x] + x (rand-int 10)) (range 4
>  lazy-flatten
>  (take 1))
>
>
>
> Prints:
>
>
> New seq...
>
> New seq...
>
> => (8)
>
>
> I realize this is because 2 items must be taken for "concat", so there 
> would need to be another approach (this was just my best shot 
> implementation). 
>
>
> Any ideas on how to get the bottom form to only print 1 "New seq..."?
>

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Lazy Flatten; One seq at a Time

2017-11-21 Thread Matt Anderson


I have a function that is returning a lazy-seq of lazy-seq's.


(seq (seq [1 2 3]) (seq [4 5 6]) ...)


The end-user API, however, should be able to get back a lazy-seq of the 
individual items across all lazy-seq's--essentially a flattening of the 
output of my function--instead of the "top level" seqs. 


(seq [1 2 3 4 5 6 ...])

Each of the internal lazy-seq's is expensive in terms of memory usage so 
I'd like to only "load" one at a time.  I've been trying to find a way to 
only calculate one of the top-level lazy-seq's at a time and then not 
"take" the next until the user gets to the end of the first and needs the 
first item from the next (eg: (seq [4 5 6]) doesn't get calculated until we 
have consumed 3 and are asking for the next), but haven't found a way to do 
it. Best I've gotten is "loading" 2 "top level" seqs at a time and I'm 
afraid that may be the best I get, but I thought it might be an exercise 
worth presenting in case anyone had ideas. Here's a contrived example:


(defn lazy-flatten

 [coll]

 (when-let [s (seq coll)]

   (lazy-seq

 (if (seq? (first s))

   (concat (lazy-flatten (first s)) (lazy-flatten (rest s)))

   (cons (first s) (lazy-flatten (rest s)))

(->> (repeatedly
   (fn []
 (println "New seq...")
 (map (fn [x] + x (rand-int 10)) (range 4
 lazy-flatten
 (take 1))



Prints:


New seq...

New seq...

=> (8)


I realize this is because 2 items must be taken for "concat", so there 
would need to be another approach (this was just my best shot 
implementation). 


Any ideas on how to get the bottom form to only print 1 "New seq..."?

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: (flatten non-sequential) has a surprising result

2015-07-02 Thread icamts
Hi Pablo,
I think you're right. Have a look at flatten source

(defn flatten
  Takes any nested combination of sequential things (lists, vectors,
  etc.) and returns their contents as a single, flat sequence.
  (flatten nil) returns an empty sequence.
  {:added 1.2
   :static true}
  [x]
  (filter (complement sequential?)
  (rest (tree-seq sequential? seq x

it is the rest function that causes this behavior and it seems to be just 
an optimization to avoid filtering the first element of tree-seq that is 
known to be the whole sequence. A simpler definition of flatten seems to 
have the behavior you expected.

(defn flatten1 [x] (filter (complement sequential?) (tree-seq sequential? 
seq x)))




Il giorno mercoledì 1 luglio 2015 13:55:28 UTC+2, J. Pablo Fernández ha 
scritto:

 Hello Clojurists,

 Today I was surprised by the result of (flatten 1) which is '(). I was 
 expecting '(1) or an error. Talking in some other people in #clojure @ 
 clojurians.net, not everybody agrees that '(1) is a good result but that 
 '() is somewhat surprising. Would it be better if it raised an error when 
 the attribute is not sequential?


-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: (flatten non-sequential) has a surprising result

2015-07-02 Thread J . Pablo Fernández
Yes, reading the source code and trying to understand why rest was being
called there is how I came up with this case.

On 2 July 2015 at 07:54, icamts ica...@gmail.com wrote:

 Hi Pablo,
 I think you're right. Have a look at flatten source

 (defn flatten
   Takes any nested combination of sequential things (lists, vectors,
   etc.) and returns their contents as a single, flat sequence.
   (flatten nil) returns an empty sequence.
   {:added 1.2
:static true}
   [x]
   (filter (complement sequential?)
   (rest (tree-seq sequential? seq x

 it is the rest function that causes this behavior and it seems to be just
 an optimization to avoid filtering the first element of tree-seq that is
 known to be the whole sequence. A simpler definition of flatten seems to
 have the behavior you expected.

 (defn flatten1 [x] (filter (complement sequential?) (tree-seq sequential?
 seq x)))




 Il giorno mercoledì 1 luglio 2015 13:55:28 UTC+2, J. Pablo Fernández ha
 scritto:

 Hello Clojurists,

 Today I was surprised by the result of (flatten 1) which is '(). I was
 expecting '(1) or an error. Talking in some other people in #clojure @
 clojurians.net, not everybody agrees that '(1) is a good result but that
 '() is somewhat surprising. Would it be better if it raised an error when
 the attribute is not sequential?

  --
 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
 ---
 You received this message because you are subscribed to a topic in the
 Google Groups Clojure group.
 To unsubscribe from this topic, visit
 https://groups.google.com/d/topic/clojure/L6yf6iFPqe8/unsubscribe.
 To unsubscribe from this group and all its topics, send an email to
 clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/d/optout.




-- 
J. Pablo Fernández pup...@pupeno.com (http://pupeno.com)

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


(flatten non-sequential) has a surprising result

2015-07-01 Thread J . Pablo Fernández
Hello Clojurists,

Today I was surprised by the result of (flatten 1) which is '(). I was 
expecting '(1) or an error. Talking in some other people in #clojure @ 
clojurians.net, not everybody agrees that '(1) is a good result but that 
'() is somewhat surprising. Would it be better if it raised an error when 
the attribute is not sequential?

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: (flatten non-sequential) has a surprising result

2015-07-01 Thread Mikera
On Wednesday, 1 July 2015 12:55:28 UTC+1, J. Pablo Fernández wrote:

 Hello Clojurists,

 Today I was surprised by the result of (flatten 1) which is '(). I was 
 expecting '(1) or an error. Talking in some other people in #clojure @ 
 clojurians.net, not everybody agrees that '(1) is a good result but that 
 '() is somewhat surprising. Would it be better if it raised an error when 
 the attribute is not sequential?


From an array programming / core.matrix perspective '(1) would be the most 
logical result.

Consider the logical sequence:
[[[1]]] = 3 dimensional array with elements '(1) 
[[1]] = 2 dimensional array with elements '(1) 
[1] =1 dimensional array with elements '(1) 
1 = 0 dimensional array (or scalar) with elements '(1) 

I am not saying that this is necessarily the best behaviour to follow for 
flatten, but it is an analogy worth considering.


-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: (flatten non-sequential) has a surprising result

2015-07-01 Thread J . Pablo Fernández
I agree with you Mikera, it also maintains the homogeneity of always
returning a sequence but some people disagreed with it, so an error might
be better.

--
J. Pablo Fernández pup...@pupeno.com
http://pupeno.com
On Jul 1, 2015 4:22 PM, Mikera mike.r.anderson...@gmail.com wrote:

 On Wednesday, 1 July 2015 12:55:28 UTC+1, J. Pablo Fernández wrote:

 Hello Clojurists,

 Today I was surprised by the result of (flatten 1) which is '(). I was
 expecting '(1) or an error. Talking in some other people in #clojure @
 clojurians.net, not everybody agrees that '(1) is a good result but that
 '() is somewhat surprising. Would it be better if it raised an error when
 the attribute is not sequential?


 From an array programming / core.matrix perspective '(1) would be the most
 logical result.

 Consider the logical sequence:
 [[[1]]] = 3 dimensional array with elements '(1)
 [[1]] = 2 dimensional array with elements '(1)
 [1] =1 dimensional array with elements '(1)
 1 = 0 dimensional array (or scalar) with elements '(1)

 I am not saying that this is necessarily the best behaviour to follow for
 flatten, but it is an analogy worth considering.


  --
 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
 ---
 You received this message because you are subscribed to a topic in the
 Google Groups Clojure group.
 To unsubscribe from this topic, visit
 https://groups.google.com/d/topic/clojure/L6yf6iFPqe8/unsubscribe.
 To unsubscribe from this group and all its topics, send an email to
 clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/d/optout.


-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of my-flatten which uses CPS

2014-07-18 Thread Mark Phillips
I *think* I've found the answer to my own question...

In this post...

  https://groups.google.com/forum/#!topic/clojure/Cuk_bJrIq-Y

I found this link (I changed the line number)...

  
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L2589

And if the implementation of eval() within the IfExpr class is anything to 
go by...

public Object eval() {
Object t = testExpr.eval();
if(t != null  t != Boolean.FALSE)
return thenExpr.eval();
return elseExpr.eval();
}


Then I think Rich has implemented it so that nil takes priority over false.

...Which strengthens the case for choosing (if xs b a) over (if (nil? xs) a 
b).

Of course, in practice it probably makes no difference, as either will be 
very quick compared to other things going on.

Cheers,

Mark.

On Friday, 18 July 2014 14:39:53 UTC+9:30, Mark Phillips wrote:

 Thanks again - that all makes sense.

 One (hopefully) tiny question... an efficiency one... (and feel free not 
 to answer it if I've already taken up enough of your time)

 If you do that and are careful, the performance of next/nil? is slightly 
 better than rest/empty?.


 If I use the next/nil? idiom, is there a performance difference between 
 doing:

1. (if (nil? xs) a b)
2. (if xs b a)

 And a related question...  Clojure has two falsey values: nil and false. 
  I assume that low-level somewhere, when checking for falsey, an (if x a b) 
 call will do something like if x is false, short circuit to b, if x is 
 nil, short circuit to b, otherwise a.  Except, I don't know which gets 
 priority of place with the short circuits - is it false (as I've just 
 written), or is it nil?

 Actually, if I'm thinking about it correctly...

 If false takes priority then...  A branch to a will take three tests for 
 1. and two tests for 2  And a branch to b will take two tests for 1. 
 and two tests for 2..

 If nil takes priority then...  A branch to a will take three tests for 
 1. and one test for 2  And a branch to b will take three tests for 1. 
 and two tests for 2..

 So 2. is always as good or better than 1. I think - performance wise.

 Of course, these things are very much minor factors in overall performance 
 (especially when things like immutable data structures are involved), but I 
 wouldn't mind knowing.

 Cheers,

 Mark.



-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of my-flatten which uses CPS

2014-07-18 Thread Mark Engelberg
Yeah, you've answered your own question.  In practice, I doubt the
difference is measurable.

Another common idiom you see in Clojure code is:
(defn f [xs]
  (if-let [s (seq xs)]
...do something with (first s) and (f (rest s))...
...base case...))

This ensures that you seq-ify the input (rather than assuming it has been
seq'ed before passed in), gives you the fast test against nil, and uses
rest rather than next because next would have the effect of causing an
extra unnecessary call to seq.

In a loop-recur situation, it is more common to do the seq once in the
initialization of the loop and then use next which calls seq:

(defn f [xs]
  (loop [s (seq xs)]
(if s
   ... (recur (next s))...
   ... base case ...)))


Out of habit, I prefer to see the base case first so I don't usually do
either of these, but these two patterns are a very popular style, and very
fast execution.  If you don't have a pre-existing preference, these would
be good choices.

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of my-flatten which uses CPS

2014-07-18 Thread Mark Phillips
Thanks - useful idioms to know about!

On Friday, 18 July 2014 16:18:33 UTC+9:30, puzzler wrote:

 Yeah, you've answered your own question.  In practice, I doubt the 
 difference is measurable.

 Another common idiom you see in Clojure code is:
 (defn f [xs]
   (if-let [s (seq xs)]
 ...do something with (first s) and (f (rest s))...
 ...base case...))

 This ensures that you seq-ify the input (rather than assuming it has been 
 seq'ed before passed in), gives you the fast test against nil, and uses 
 rest rather than next because next would have the effect of causing an 
 extra unnecessary call to seq.

 In a loop-recur situation, it is more common to do the seq once in the 
 initialization of the loop and then use next which calls seq:

 (defn f [xs]
   (loop [s (seq xs)]
 (if s
... (recur (next s))...
... base case ...)))


 Out of habit, I prefer to see the base case first so I don't usually do 
 either of these, but these two patterns are a very popular style, and very 
 fast execution.  If you don't have a pre-existing preference, these would 
 be good choices.
  

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of my-flatten which uses CPS

2014-07-17 Thread Mark Engelberg
Right.  Overall lessons:

In recursion, the call stack automatically keeps track of what still needs
to be done.
In Clojure, due to Java, the stack is significantly more limited than heap,
so this can be a real limitation.
To break free of that limitation, you must somehow keep track of what still
needs to be done in a heap-allocated data structure.
CPS is one way to do that, effectively using closures wrapping other
closures to create a stack of things that need to be done.
Unfortunately, CPS is usually not very useful in Clojure -- when the
closures are executed you are again using Clojure's severely-limited stack
to perform that execution, so you'll blow the stack then.
So the better solution is to think explicitly about what kind of remains
to be done information needs to be tracked, and just track that
information in a heap-allocated data structure.

So CPS is a good starting point for reasoning about a recursion problem,
but ultimately, you want to convert it into some sort of accumulator.

I'm not sure I see the utility of the CPS/accumulator hybrid model you
proposed.  I think the goal is to get away from CPS once you understand
what is going on behind the scenes.

I saw an interesting analysis once of the factorial function, starting from
the recursive formulation of the function, then doing CPS, then doing an
analysis of exactly what values need to be tracked by the continuations,
and then eliminating the actual continuations.  What you are left with is a
version of the function that begins by building a heap-allocated structure
of all the numbers from 1 to n, and then just reduces them with
multiplication, which is basically what you'd expect the concise version of
the function to be.  I think that's a great example to keep in mind.



On Wed, Jul 16, 2014 at 8:39 PM, Mark P pierh...@gmail.com wrote:

 Interesting - thank you!

 Good to know about into as a way to achieve a non-lazy concat - in
 conjunction with a vector.

 I like your accumulator version - morphing the structure of the input as
 you go to achieve the desired result.

 I've come up with another version, that passes through both a result so
 far accumulator and a still to be computed stack.  It is very much
 non-lazy, but that's okay in some applications (a performance feature
 even!).  Here it is...

 (defn my-accandstackbased-flatten
   [xs]
   (letfn [(flatten-accandstack [xs accvec stackvec]
 (if (empty? xs)
   (if (empty? stackvec)
 accvec
 (recur (peek stackvec) accvec (pop stackvec)))
   (let [x (first xs), ys (next xs)]
 (if (sequential? x)
   (recur x accvec (conj stackvec ys))
   (recur ys (conj accvec x) stackvec)]
 (seq (flatten-accandstack xs [] []

 This has nice recur behaviour and doesn't mess too much with the structure
 of the input nested lists.  In the case of flatten, retaining structure is
 not important (as you nicely illustrated), but there are generalizations of
 this kind of function where retaining structure becomes more important.

 Now here's the thing...  In the above, my stackvec is sort of like a
 continuation.  It contains a stack of computation to be performed later on.
  That sounds very much like a continuation to me (though I am still in the
 process of getting my head around this stuff).  So I've thought, surely I
 could write an acc and cps version of my-flatten?  Here is what I came up
 with...

 (defn my-accandcpsbased-flatten
   [xs]
   (letfn [(flatten-accandcps [xs accvec k]
 (if (empty? xs)
   (k accvec)
   (let [x (first xs), ys (next xs)]
 (if (sequential? x)
   (recur x accvec (fn [v] (flatten-accandcps ys [] (fn [w]
 (k (into v w))
   (recur ys (conj accvec x) k)]
 (seq (flatten-accandcps xs [] identity

 And I could do the trick you showed me with thunks and a trampoline, if I
 wanted to make it completely stack-avoiding.

 What does this show?  I'm not sure.

 Presumably the acc and stack version is the most efficient as it uses
 recur everywhere?

 The structure of the continuation I pass in with the acc and cps version
 is very similar in complexity to the continuation I passed as part of my
 original cps implementation.  So where's the gain?  I guess the inclusion
 of an accvec means that continuations are generated less frequently so that
 the overall size and execution time of continuations is smaller?  And it is
 an improvement over my earlier aps version that used only an acc vector -
 because this version has everything in tail-call position and is amenable
 to trampolining.

 Is this attempt at analysis reasonable?  Is there anything else worth
 observing etc?

 Presumably I could make the acc and cps above more lazy using concat,
 cons and lazy-seq.  I'd need to think about how easy/hard it would be to
 make my acc and stack version as lazy

Re: Critiques of my-flatten which uses CPS

2014-07-17 Thread Steve Miner
Slightly off-topic from original poster's question, but if you're interested in 
another  implementation of flatten, I suggest you take a look at the reducers 
library.  clojure.core/flatten is elegant but a bit slow.  The reducers version 
is very fast as part of a reduce/fold operation.  The whole reducers library is 
worth studying.

http://clojure.org/reducers

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of my-flatten which uses CPS

2014-07-17 Thread Raoul Duke
 http://clojure.org/reducers

i dare say the When to use part should not be at the bottom but come
right after the otherwise laughably specious yielding code that will
get faster automatically as machines get more cores.

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of my-flatten which uses CPS

2014-07-17 Thread Mark P
Coming back to your helpful comments about relationship between acc-style 
and lazy...

It's worth understanding how to go back and forth between accumulator-style 
 and a lazy construction.  You can convert the above non-lazy accumulator 
 version into a similar version that is lazy but has no risk of stack 
 overflow in the realization of that lazy flattened list:


I notice in your lazy version (below), you preface the last cons with a 
lazy-seq call, but do not do the same with the other cons calls (within the 
first recur form).  I know it was only the last line that previously had a 
conj call and so participated in this transformation... but I'm wondering 
why you wouldn't also use lazy-seq with the other cons-involving line?

To answer my own wondering, I am thinking it is for two reasons:

   1. The main reason for using lazy-seq in the last line is to defer the 
   recursive call to my-flatten until something wants to use it.  In contrast, 
   the other cons-involving line only conses up things which are relatively 
   harmless to evaluate.
   2. The cons (first x) ... will be undone almost immediately after 
   the recur is executed, via the (first xs).  So inserting laziness here is 
   counter productive.

Another question...

I notice that you bound ys to (rest xs), in contrast to my choice of (next 
xs) in some of my implementations.  I realize this is probably a minor 
point, but just wondering whether (rest xs) was a deliberate choice of 
yours, or just habit.  I realize that rest maximizes laziness in contrast 
to next, but do we want maximum laziness here?

To again attempt to answer my own question...  It probably depends on what 
xs is being passed into my-flatten.  It xs is a fully realized sequence, 
then (next x) would probably do.  But if xs is itself lazy (and possibly 
expensive to compute), then using (rest x) maximizes our laziness 
opportunity.

Maybe the thing to do would be to use (next x) here for this 
implementation, which is angling to be lazy...  But in your earlier 
acc-based my-flatten, to use (next x) instead, because this implementation 
is eager and we know we're going to realize all of xs at some point anyway. 
 It this logic sound?  (I realize I am being pedantic, but I'm trying to 
understand the principles involved.)

Thanks again for showing me the relationship between acc-based and lazy - 
helpful!


 (defn my-flatten
   [xs]
   (if (empty? xs) ()
 (let [x (first xs), ys (rest xs)]
   (if (sequential? x)
 (if (seq x)
   (recur (cons (first x) (cons (rest x) ys)))
   (recur ys))
 (lazy-seq (cons x (my-flatten ys)))

 Basically, you just get rid of the accumulator, and in the place where you 
 would have conj'd in the next atomic element, you just build the lazy 
 sequence.



-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of my-flatten which uses CPS

2014-07-17 Thread Mark P
Woopse, typo towards the end of my last post...

Maybe the thing to do would be to use (next x) here for this 
 implementation, which is angling to be lazy...  But in your earlier 
 acc-based my-flatten, to use (next x) instead


Should be...  Maybe the thing to do would be to use (rest x) ...

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of my-flatten which uses CPS

2014-07-17 Thread Mark P
One other question occurs to me re your comment...

It's worth understanding how to go back and forth between accumulator-style 
 and a lazy construction.  You can convert the above non-lazy accumulator 
 version into a similar version that is lazy but has no risk of stack 
 overflow in the realization of that lazy flattened list:


Why does going lazy avoid a stack overflow risk?

Again, to answer my own question :-) ...  The resultant flat list from 
my-flatten will be realized one element at a time.  The call stack will be 
used during this process, but lazy-seq prevents it getting very deep.  I 
think lazy-seq is a bit like a thunk (invoked via the seq call), except 
that it also caches the result.  So its like the thunks in our 
trampolining, except that the bouncing doesn't occur eagerly as with 
trampolining, but only on-demand as a consumer traverses the flat list.

Is this a good way of thinking about it?
 


 (defn my-flatten
   [xs]
   (if (empty? xs) ()
 (let [x (first xs), ys (rest xs)]
   (if (sequential? x)
 (if (seq x)
   (recur (cons (first x) (cons (rest x) ys)))
   (recur ys))
 (lazy-seq (cons x (my-flatten ys)))

 Basically, you just get rid of the accumulator, and in the place where you 
 would have conj'd in the next atomic element, you just build the lazy 
 sequence.



-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of my-flatten which uses CPS

2014-07-17 Thread Mark Engelberg
On Thu, Jul 17, 2014 at 7:54 PM, Mark P pierh...@gmail.com wrote:


 I notice in your lazy version (below), you preface the last cons with a
 lazy-seq call, but do not do the same with the other cons calls (within the
 first recur form).  I know it was only the last line that previously had a
 conj call and so participated in this transformation... but I'm wondering
 why you wouldn't also use lazy-seq with the other cons-involving line?


The lazy-seq is necessary because of the recursive call that isn't in
tail-call position (so you can't use recur).  One way to think about it is
that at that point, we know what the first element of the sequence is going
to be, so the lazy-seq lets us return immediately with the computed first
element and a description of the further computation that can compute the
rest on demand.

lazy-seq is the secret sauce that makes it so non-tail recursive calls
don't overflow the stack.  That's because the sequence is prompted for one
element at a time from an outside consumer -- as you noted in one of your
messages, it's a lot like what trampolining does.  So to make sure you
don't have stack overflow, all you have to do is make sure that you use
bounded stack space in the process of computing the next element.

The other calls to cons are just part of the process of coming up with the
next element, basically sticking stuff to be computed on the front of the
list as a trick to avoid a separate accumulator.  Because they are inside a
recur, no additional stack is consumed (the list grows, but that's a
heap-allocated data structure, so not a problem).






 Another question...

 I notice that you bound ys to (rest xs), in contrast to my choice of (next
 xs) in some of my implementations.  I realize this is probably a minor
 point, but just wondering whether (rest xs) was a deliberate choice of
 yours, or just habit.  I realize that rest maximizes laziness in contrast
 to next, but do we want maximum laziness here?


One idiom is to use to use (next xs), and then you can test against it
being nil to determine whether it is empty or not.  But to use that idiom,
you have to be very careful to make sure you call seq on the sequence that
is passed as an input to the function (which you did in your version).  If
you do that and are careful, the performance of next/nil? is slightly
better than rest/empty?.  But I've gotten burned enough times, I simply
prefer to use empty? as my test, and then you might as well use rest rather
than next.  It's my own preference.  I think many people in the Clojure
community prefer to seq the input and then next/nil?.  Either is fine.

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of my-flatten which uses CPS

2014-07-17 Thread Mark Phillips
Thanks again - that all makes sense.

One (hopefully) tiny question... an efficiency one... (and feel free not to 
answer it if I've already taken up enough of your time)

If you do that and are careful, the performance of next/nil? is slightly 
 better than rest/empty?.


If I use the next/nil? idiom, is there a performance difference between 
doing:

   1. (if (nil? xs) a b)
   2. (if xs b a)

And a related question...  Clojure has two falsey values: nil and false.  I 
assume that low-level somewhere, when checking for falsey, an (if x a b) 
call will do something like if x is false, short circuit to b, if x is 
nil, short circuit to b, otherwise a.  Except, I don't know which gets 
priority of place with the short circuits - is it false (as I've just 
written), or is it nil?

Actually, if I'm thinking about it correctly...

If false takes priority then...  A branch to a will take three tests for 
1. and two tests for 2  And a branch to b will take two tests for 1. 
and two tests for 2..

If nil takes priority then...  A branch to a will take three tests for 1. 
and one test for 2  And a branch to b will take three tests for 1. 
and two tests for 2..

So 2. is always as good or better than 1. I think - performance wise.

Of course, these things are very much minor factors in overall performance 
(especially when things like immutable data structures are involved), but I 
wouldn't mind knowing.

Cheers,

Mark.

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of my-flatten which uses CPS

2014-07-16 Thread Mark Engelberg
It's worth understanding how to go back and forth between accumulator-style
and a lazy construction.  You can convert the above non-lazy accumulator
version into a similar version that is lazy but has no risk of stack
overflow in the realization of that lazy flattened list:

(defn my-flatten
  [xs]
  (if (empty? xs) ()
(let [x (first xs), ys (rest xs)]
  (if (sequential? x)
(if (seq x)
  (recur (cons (first x) (cons (rest x) ys)))
  (recur ys))
(lazy-seq (cons x (my-flatten ys)))

Basically, you just get rid of the accumulator, and in the place where you
would have conj'd in the next atomic element, you just build the lazy
sequence.

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of my-flatten which uses CPS

2014-07-16 Thread Mark P
Interesting - thank you!

Good to know about into as a way to achieve a non-lazy concat - in 
conjunction with a vector.

I like your accumulator version - morphing the structure of the input as 
you go to achieve the desired result.

I've come up with another version, that passes through both a result so 
far accumulator and a still to be computed stack.  It is very much 
non-lazy, but that's okay in some applications (a performance feature 
even!).  Here it is...

(defn my-accandstackbased-flatten
  [xs]
  (letfn [(flatten-accandstack [xs accvec stackvec]
(if (empty? xs)
  (if (empty? stackvec)
accvec
(recur (peek stackvec) accvec (pop stackvec)))
  (let [x (first xs), ys (next xs)]
(if (sequential? x)
  (recur x accvec (conj stackvec ys))
  (recur ys (conj accvec x) stackvec)]
(seq (flatten-accandstack xs [] []

This has nice recur behaviour and doesn't mess too much with the structure 
of the input nested lists.  In the case of flatten, retaining structure is 
not important (as you nicely illustrated), but there are generalizations of 
this kind of function where retaining structure becomes more important.

Now here's the thing...  In the above, my stackvec is sort of like a 
continuation.  It contains a stack of computation to be performed later on. 
 That sounds very much like a continuation to me (though I am still in the 
process of getting my head around this stuff).  So I've thought, surely I 
could write an acc and cps version of my-flatten?  Here is what I came up 
with...

(defn my-accandcpsbased-flatten
  [xs]
  (letfn [(flatten-accandcps [xs accvec k]
(if (empty? xs)
  (k accvec)
  (let [x (first xs), ys (next xs)]
(if (sequential? x)
  (recur x accvec (fn [v] (flatten-accandcps ys [] (fn [w] 
(k (into v w))
  (recur ys (conj accvec x) k)]
(seq (flatten-accandcps xs [] identity
 
And I could do the trick you showed me with thunks and a trampoline, if I 
wanted to make it completely stack-avoiding.

What does this show?  I'm not sure.

Presumably the acc and stack version is the most efficient as it uses recur 
everywhere?

The structure of the continuation I pass in with the acc and cps version 
is very similar in complexity to the continuation I passed as part of my 
original cps implementation.  So where's the gain?  I guess the inclusion 
of an accvec means that continuations are generated less frequently so that 
the overall size and execution time of continuations is smaller?  And it is 
an improvement over my earlier aps version that used only an acc vector - 
because this version has everything in tail-call position and is amenable 
to trampolining.

Is this attempt at analysis reasonable?  Is there anything else worth 
observing etc?

Presumably I could make the acc and cps above more lazy using concat, 
cons and lazy-seq.  I'd need to think about how easy/hard it would be to 
make my acc and stack version as lazy.

Thanks again for your helpful comments and examples.

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Critiques of my-flatten which uses CPS

2014-07-15 Thread Mark P
I'm very new to continuation passing style (CPS), and as part of the 
learning process I've done a CPS version of a flatten function.  Ie, it 
does the same thing as the standard clojure flatten, but is implemented 
using a recursive local CPS helper function.  I'm interested in comments / 
critiques on what I've done.

Here it is...

(defn my-flatten
  [xs]
  (letfn [(my-flatten-cps [xs k]
(if (nil? xs)
  (k '())
  (let [x (first xs), ys (next xs)]
(if (sequential? x)
  (recur ys (fn [v] (my-flatten-cps (seq x) (fn [w] (k 
(concat w v))
  (recur ys (fn [v] (k (conj v x]
(my-flatten-cps (seq xs) identity)))

I'm relatively inexperienced with clojure, so please feel free to suggest 
improvements to my clojure code.

But what I'm most interested in is understanding CPS better and about how 
it interacts with Clojure and with recur.  As you can see, my-flatten-cps 
uses recur nicely to traverse at a breadth level.  But as we sink down into 
depth, I've done an actual non-recur call to my-flatten-cps.  I presume I 
can't do a recur here instead (because it would attempt to jump to the most 
immediate fn??) - is this correct?

Is there any way around this?  (As I write this, the word trampoline 
comes to mind - some videos I've watched speak of this - but not sure how 
this would work and what efficiency trade-offs would be involved.)

The other things is... is it so bad that it is not fully using recur - 
maybe using a bit of stack is okay??

Thanks,

Mark.

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of my-flatten which uses CPS

2014-07-15 Thread Mark Engelberg
Yes, here's the trampolined version which won't stack overflow:

(defn my-flatten
  [xs]
  (letfn [(my-flatten-cps [xs k]
(if (nil? xs)
  (k '())
  (let [x (first xs), ys (next xs)]
(if (sequential? x)
  (recur ys (fn [v] (fn [] (my-flatten-cps (seq x) (fn [w]
(fn [] (k (doall (concat w v)
  (recur ys (fn [v] #(k (conj v x]
(trampoline my-flatten-cps (seq xs) identity)))

Basically, you just wrap the body of each continuation in a function of no
arguments, and call the recursive function with trampoline.

Another thing you have to do is wrap the concat in a doall, otherwise
you'll get a stack overflow when the deeply nested lazy concatenation is
realized.


On Tue, Jul 15, 2014 at 12:13 AM, Mark P pierh...@gmail.com wrote:

 I'm very new to continuation passing style (CPS), and as part of the
 learning process I've done a CPS version of a flatten function.  Ie, it
 does the same thing as the standard clojure flatten, but is implemented
 using a recursive local CPS helper function.  I'm interested in comments /
 critiques on what I've done.

 Here it is...

 (defn my-flatten
   [xs]
   (letfn [(my-flatten-cps [xs k]
 (if (nil? xs)
   (k '())
   (let [x (first xs), ys (next xs)]
 (if (sequential? x)
   (recur ys (fn [v] (my-flatten-cps (seq x) (fn [w] (k
 (concat w v))
   (recur ys (fn [v] (k (conj v x]
 (my-flatten-cps (seq xs) identity)))

 I'm relatively inexperienced with clojure, so please feel free to suggest
 improvements to my clojure code.

 But what I'm most interested in is understanding CPS better and about how
 it interacts with Clojure and with recur.  As you can see, my-flatten-cps
 uses recur nicely to traverse at a breadth level.  But as we sink down into
 depth, I've done an actual non-recur call to my-flatten-cps.  I presume I
 can't do a recur here instead (because it would attempt to jump to the most
 immediate fn??) - is this correct?

 Is there any way around this?  (As I write this, the word trampoline
 comes to mind - some videos I've watched speak of this - but not sure how
 this would work and what efficiency trade-offs would be involved.)

 The other things is... is it so bad that it is not fully using recur -
 maybe using a bit of stack is okay??

 Thanks,

 Mark.

  --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/d/optout.


-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of my-flatten which uses CPS

2014-07-15 Thread Jonathan Fischer Friberg
I haven't really used CPS myself, but I think you should be able to use the
trampoline function to clean up your code.

http://clojuredocs.org/clojure_core/clojure.core/trampoline

Jonathan


On 15 July 2014 09:13, Mark P pierh...@gmail.com wrote:

 I'm very new to continuation passing style (CPS), and as part of the
 learning process I've done a CPS version of a flatten function.  Ie, it
 does the same thing as the standard clojure flatten, but is implemented
 using a recursive local CPS helper function.  I'm interested in comments /
 critiques on what I've done.

 Here it is...

 (defn my-flatten
   [xs]
   (letfn [(my-flatten-cps [xs k]
 (if (nil? xs)
   (k '())
   (let [x (first xs), ys (next xs)]
 (if (sequential? x)
   (recur ys (fn [v] (my-flatten-cps (seq x) (fn [w] (k
 (concat w v))
   (recur ys (fn [v] (k (conj v x]
 (my-flatten-cps (seq xs) identity)))

 I'm relatively inexperienced with clojure, so please feel free to suggest
 improvements to my clojure code.

 But what I'm most interested in is understanding CPS better and about how
 it interacts with Clojure and with recur.  As you can see, my-flatten-cps
 uses recur nicely to traverse at a breadth level.  But as we sink down into
 depth, I've done an actual non-recur call to my-flatten-cps.  I presume I
 can't do a recur here instead (because it would attempt to jump to the most
 immediate fn??) - is this correct?

 Is there any way around this?  (As I write this, the word trampoline
 comes to mind - some videos I've watched speak of this - but not sure how
 this would work and what efficiency trade-offs would be involved.)

 The other things is... is it so bad that it is not fully using recur -
 maybe using a bit of stack is okay??

 Thanks,

 Mark.

  --
 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
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/d/optout.


-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of my-flatten which uses CPS

2014-07-15 Thread Mark P
Thanks for explaining how one creates a trampolined version from the cps 
version!  This makes sense.

Thanks also for alerting me to potential issues with the concat laziness. 
 From a code efficiency point of view, producing a lazy something and then 
immediately evaluating it is inefficient.  It is better to use a strict 
version of the something in the first place.  Does Clojure provide strict 
versions of things like concat, or would I need to roll-my-own?

Thinking again of efficiency... I had a go at doing an 
accumulator-passing-style (APS) version of flatten.  Here it is...

(defn my-apsbased-flatten
  [xs]
  (letfn [(my-flatten-aps [xs avec]
(if (nil? xs)
  avec
  (let [x (first xs), ys (next xs)]
(if (sequential? x)
  (recur ys (into avec (my-flatten-aps (seq x) '[])))
  (recur ys (conj avec x))]
(seq (my-flatten-aps (seq xs) '[]

This is more efficient (I think) than my earlier cps-based flatten.  But it 
has the problem again of using the stack via the non-recur call to 
my-flatten-aps.

I'm wondering if it's somehow possible to modify this aps implementation to 
also use trampolining?

Alternatively, maybe there's a combination aps-cps variation which can be 
trampolined??  I've had a bit of a go at this and so far can't see how to 
do it.  Perhaps not, as APS seems to do pre-calculation whereas CPS seems 
to do post-calculation?

But I can't help thinking that there must be a more efficient trampolined 
version of flatten that utilizes the structure of the flatten problem 
more, like APS does?

Cheers,

Mark.

On Tuesday, 15 July 2014 19:25:26 UTC+9:30, puzzler wrote:

 Yes, here's the trampolined version which won't stack overflow:

 (defn my-flatten
   [xs]
   (letfn [(my-flatten-cps [xs k]
 (if (nil? xs)
   (k '())
   (let [x (first xs), ys (next xs)]
 (if (sequential? x)
   (recur ys (fn [v] (fn [] (my-flatten-cps (seq x) (fn [w] 
 (fn [] (k (doall (concat w v)
   (recur ys (fn [v] #(k (conj v x]
 (trampoline my-flatten-cps (seq xs) identity)))

 Basically, you just wrap the body of each continuation in a function of no 
 arguments, and call the recursive function with trampoline.

 Another thing you have to do is wrap the concat in a doall, otherwise 
 you'll get a stack overflow when the deeply nested lazy concatenation is 
 realized.


 On Tue, Jul 15, 2014 at 12:13 AM, Mark P pier...@gmail.com javascript: 
 wrote:

 I'm very new to continuation passing style (CPS), and as part of the 
 learning process I've done a CPS version of a flatten function.  Ie, it 
 does the same thing as the standard clojure flatten, but is implemented 
 using a recursive local CPS helper function.  I'm interested in comments / 
 critiques on what I've done.

 Here it is...

 (defn my-flatten
   [xs]
   (letfn [(my-flatten-cps [xs k]
 (if (nil? xs)
   (k '())
   (let [x (first xs), ys (next xs)]
 (if (sequential? x)
   (recur ys (fn [v] (my-flatten-cps (seq x) (fn [w] (k 
 (concat w v))
   (recur ys (fn [v] (k (conj v x]
 (my-flatten-cps (seq xs) identity)))

 I'm relatively inexperienced with clojure, so please feel free to suggest 
 improvements to my clojure code.

 But what I'm most interested in is understanding CPS better and about how 
 it interacts with Clojure and with recur.  As you can see, my-flatten-cps 
 uses recur nicely to traverse at a breadth level.  But as we sink down into 
 depth, I've done an actual non-recur call to my-flatten-cps.  I presume I 
 can't do a recur here instead (because it would attempt to jump to the most 
 immediate fn??) - is this correct?

 Is there any way around this?  (As I write this, the word trampoline 
 comes to mind - some videos I've watched speak of this - but not sure how 
 this would work and what efficiency trade-offs would be involved.)

 The other things is... is it so bad that it is not fully using recur - 
 maybe using a bit of stack is okay??

 Thanks,

 Mark.

  -- 
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clo...@googlegroups.com 
 javascript:
 Note that posts from new members are moderated - please be patient with 
 your first post.
 To unsubscribe from this group, send email to
 clojure+u...@googlegroups.com javascript:
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 --- 
 You received this message because you are subscribed to the Google Groups 
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an 
 email to clojure+u...@googlegroups.com javascript:.
 For more options, visit https://groups.google.com/d/optout.




-- 
You received this message because you are subscribed

Re: Critiques of my-flatten which uses CPS

2014-07-15 Thread Mark Engelberg
To avoid the doall-concat, you'd just have the base case return [] (btw,
you don't need the apostrophe for vectors or for the empty list), and use
`into` rather than `concat`.

If you're looking for something that exploits the structure of flatten and
uses an accumulator, you could do this:

(defn my-flatten
  [xs]
  (letfn [(my-flatten-aps [xs avec]
(if (empty? xs)
  avec
  (let [x (first xs), ys (rest xs)]
(if (sequential? x)
  (if (seq x)
(recur (cons (first x) (cons (rest x) ys)) avec)
(recur ys avec))
  (recur ys (conj avec x))]
(my-flatten-aps xs [])))

The idea is that if you have a non-empty sequence in the first position,
you pull out its first element and stick it on the front of the overall
sequence.

So ((1 2 3) 4 5) will recur as (1 (2 3) 4 5).
The next go around will pick up that 1 is atomic and add it to the
accumulator, and so on.

If you have an empty sequence in the first position, you just skip over it
entirely.

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


another why: (flatten #{:a :b}) = () ???

2012-08-29 Thread dmirylenka
Calling flatten on anything that is not 'sequential?' returns an empty 
sequence:

(flatten 1); = () 
(flatten Hi); = () 

With sets if feels somewhat strange:

(flatten #{#{:a} #{:b :c}}); = ()

For some reason I expected #{#{:a} #{:b :c}} to equal #{:a :b :c}.

Ok, the docstring says: Takes any nested combination of sequential 
things..., and sets are not sequential...

But then, why

(reduce + (flatten #{1 2})); = 0
(r/reduce + (r/flatten #{1 2})); = 3 ?

-- 
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: another why: (flatten #{:a :b}) = () ???

2012-08-29 Thread Steve Miner
flatten has been discussed before:

https://groups.google.com/forum/?fromgroups=#!topic/clojure/ye70iNJ73zc

See also CLJ-400, but it looks like no patch was submitted.

http://dev.clojure.org/jira/browse/CLJ-400

I think the general policy for Clojure is that the core functions of course 
should work as documented, but they do not necessarily handle undocumented edge 
cases.  So if you use the wrong kinds of arguments, the implementation does not 
have to detect your error -- it might throw or just give you non-useful 
results.  There's a trade-off among ease of implementation, performance and 
programmer friendliness.  If it's a common mistake, maybe an assertion is 
warranted.  If I remember correctly, Rich Hickey suggested that someday there 
might be an option to run a stricter version of Clojure (with lots of 
assertions) during development, and a faster version with less checking in 
production.

Regarding flatten in particular, I would like it to be faster and to do a bit 
more to help the careless programmer.  I was all set to submit a patch 
condemning the elegant but slow implementation when I noticed that the new 
reducers version of flatten in 1.5 alphas is amazingly fast.  So that looks 
like the way to go.



On Aug 29, 2012, at 3:47 PM, dmirylenka daniilmirile...@gmail.com wrote:

 Calling flatten on anything that is not 'sequential?' returns an empty 
 sequence:
 
 (flatten 1); = () 
 (flatten Hi); = () 
 
 With sets if feels somewhat strange:
 
 (flatten #{#{:a} #{:b :c}}); = ()
 
 For some reason I expected #{#{:a} #{:b :c}} to equal #{:a :b :c}.
 
 Ok, the docstring says: Takes any nested combination of sequential 
 things..., and sets are not sequential...
 
 But then, why
 
 (reduce + (flatten #{1 2})); = 0
 (r/reduce + (r/flatten #{1 2})); = 3 ?

-- 
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: another why: (flatten #{:a :b}) = () ???

2012-08-29 Thread dmirylenka
Thanks for the elaborate answer!
It also clears some other doubts I had regarding the core functions.

On Wednesday, August 29, 2012 11:34:56 PM UTC+2, miner wrote:

 flatten has been discussed before: 

 https://groups.google.com/forum/?fromgroups=#!topic/clojure/ye70iNJ73zc 

 See also CLJ-400, but it looks like no patch was submitted. 

 http://dev.clojure.org/jira/browse/CLJ-400 

 I think the general policy for Clojure is that the core functions of 
 course should work as documented, but they do not necessarily handle 
 undocumented edge cases.  So if you use the wrong kinds of arguments, the 
 implementation does not have to detect your error -- it might throw or just 
 give you non-useful results.  There's a trade-off among ease of 
 implementation, performance and programmer friendliness.  If it's a common 
 mistake, maybe an assertion is warranted.  If I remember correctly, Rich 
 Hickey suggested that someday there might be an option to run a stricter 
 version of Clojure (with lots of assertions) during development, and a 
 faster version with less checking in production. 

 Regarding flatten in particular, I would like it to be faster and to do a 
 bit more to help the careless programmer.  I was all set to submit a patch 
 condemning the elegant but slow implementation when I noticed that the new 
 reducers version of flatten in 1.5 alphas is amazingly fast.  So that 
 looks like the way to go. 



 On Aug 29, 2012, at 3:47 PM, dmirylenka daniilm...@gmail.comjavascript: 
 wrote: 

  Calling flatten on anything that is not 'sequential?' returns an empty 
 sequence: 
  
  (flatten 1); = () 
  (flatten Hi); = () 
  
  With sets if feels somewhat strange: 
  
  (flatten #{#{:a} #{:b :c}}); = () 
  
  For some reason I expected #{#{:a} #{:b :c}} to equal #{:a :b :c}. 
  
  Ok, the docstring says: Takes any nested combination of sequential 
 things..., and sets are not sequential... 
  
  But then, why 
  
  (reduce + (flatten #{1 2})); = 0 
  (r/reduce + (r/flatten #{1 2})); = 3 ? 



-- 
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

How to flatten a nested sequence?

2011-10-04 Thread Shoeb Bhinderwala
(def s1
  (seq
[s1
   (seq [s2 s3]) s4 s5 (seq [s6 (seq [s7 s8])
s9])]))

user = s1
(s1 (s2 s3) s4 s5 (s6 (s7 s8) s9))

How to convert s1 to a flat sequence like this:

(s1 s2 s3 s4 s5 s6 s7 s8 s9)

-- 
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: How to flatten a nested sequence?

2011-10-04 Thread Jack Moffitt
 user = s1
 (s1 (s2 s3) s4 s5 (s6 (s7 s8) s9))

 How to convert s1 to a flat sequence like this:

 (s1 s2 s3 s4 s5 s6 s7 s8 s9)

(flatten s1)

jack.

-- 
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: How to flatten a nested sequence?

2011-10-04 Thread Michał Marczyk
user= (flatten s1)
(s1 s2 s3 s4 s5 s6 s7 s8 s9)

Sincerely,
Michał

-- 
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: How to flatten a nested sequence?

2011-10-04 Thread Ulises
your subject contains the answer :)

sandbox (def s1 (seq [s1 (seq [s2 s3]) s4 s5 (seq [s6
(seq [s7 s8]) s9])]))
#'sandbox/s1
sandbox s1
(s1 (s2 s3) s4 s5 (s6 (s7 s8) s9))
sandbox (flatten s1)
(s1 s2 s3 s4 s5 s6 s7 s8 s9)
sandbox (doc flatten)
-
clojure.core/flatten
([x])
  Takes any nested combination of sequential things (lists, vectors,
  etc.) and returns their contents as a single, flat sequence.
  (flatten nil) returns nil.
nil
sandbox

-- 
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: How to flatten a nested sequence?

2011-10-04 Thread Shoeb Bhinderwala
Thanks. Didn't think it would exist in clojure.core.

On Oct 4, 4:58 pm, Ulises ulises.cerv...@gmail.com wrote:
 your subject contains the answer :)

 sandbox (def s1 (seq [s1 (seq [s2 s3]) s4 s5 (seq [s6
 (seq [s7 s8]) s9])]))
 #'sandbox/s1
 sandbox s1
 (s1 (s2 s3) s4 s5 (s6 (s7 s8) s9))
 sandbox (flatten s1)
 (s1 s2 s3 s4 s5 s6 s7 s8 s9)
 sandbox (doc flatten)
 -
 clojure.core/flatten
 ([x])
   Takes any nested combination of sequential things (lists, vectors,
   etc.) and returns their contents as a single, flat sequence.
   (flatten nil) returns nil.
 nil
 sandbox

-- 
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: How to flatten a nested sequence?

2011-10-04 Thread Sean Corfield
On Tue, Oct 4, 2011 at 2:25 PM, Shoeb Bhinderwala
shoeb.bhinderw...@gmail.com wrote:
 Thanks. Didn't think it would exist in clojure.core.

I highly recommend trying out Chas Emerick's Clojure Atlas:
http://clojureatlas.com - it makes searching for functions AND
concepts really easy and provides a great way to see the relationships
between different parts of the Clojure core and ecosystem.

Caveat: I'm a big enough fan of the atlas to be a paying customer but
the free version is full-featured (it just has an occasional 'nag'
reminder).
-- 
Sean A Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/
World Singles, LLC. -- http://worldsingles.com/
Railo Technologies, Inc. -- http://www.getrailo.com/

Perfection is the enemy of the good.
-- Gustave Flaubert, French realist novelist (1821-1880)

-- 
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: (flatten )

2011-09-30 Thread Tassilo Horn
ChrisR christopher.roseng...@gmail.com writes:

 Hi there, possibly the flatten documentation is wrong as (flatten nil)
 for me is returning the empty list rather than nil. (1.3.0).

Indeed, that's because it uses `filter' which produces a lazy seq.  Most
probably, in this case it's just the docstring that should be fixed.

 Is there a better place to post this?

If no core team member picks up the issue, maybe add it to the issue
tracker.

  http://dev.clojure.org/jira

Bye,
Tassilo

-- 
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


(flatten )

2011-09-29 Thread ChrisR
Hi there, possibly the flatten documentation is wrong as (flatten nil)
for me is returning
the empty list rather than nil. (1.3.0). Is there a better place to
post this?

  (clojure.core/flatten nil)
  = ()

from docstring:
  Takes any nested combination of sequential things (lists, vectors,
etc.) and returns their contents as a single, flat sequence.
(flatten nil) returns 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: faster flatten?

2010-07-15 Thread Cam
You're right about rest, I didn't see that rest should be preferred to
next when consuming seqs in this style.

I agree that flatten returning the empty list for some of the things
that actually can be seqed is odd. I'm sure there's a good reason
somewhere, but it's not to hard to change by just using seqable? from
contrib. That makes flatten handle anything. After benchmarking it
though, it seems like its muuuch slower; so slow that I got bored of
waiting after 5 minutes. Seems like a punt though :/


On Jul 14, 3:55 pm, Steve Miner stevemi...@gmail.com wrote:
 On Jul 14, 2010, at 2:40 PM, Cam wrote:

  I definitely like this version a little better. If you change the else
  of the if to be just (list), it returns the empty list just as core/
  flatten does. Mind if I update the ticket with this patch?

 It's all yours.  Really, just a slight change from your code anyway.

 I wonder about the call to next.  I'm thinking it should be rest instead.  
 (Seehttp://clojure.org/lazy)

 I definitely don't like the way (flatten 10)  and (flatten {:a 1 :b 2}) 
 return the empty list (in 1.2 beta).  I think these are accidents, and I 
 worry that they will obscure higher-level bugs.

 My preference is to return the arg if it's not sequential? as I believe it 
 will provide a more useful result at no extra cost.  In that case, the 
 argument to flatten was probably a mistake, and it's better if the value 
 shows up somewhere rather than being mysteriously swallowed.  On the other 
 hand, it might make sense to return (list arg) on the theory that flatten 
 should always return a seq.  I could live with 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: faster flatten?

2010-07-14 Thread miner
I think it's worthwhile to have a faster flatten even if it doesn't
look as elegant as the current implementation.  You could do a bit of
refactoring and save yourself a call to sequential? since the
recursive calls are guaranteed to have seqs (as a result of next).

Also, I'd prefer flatten to return the argument if it isn't
sequential? so for example, (flatten 10) == 10.  I think it would be
less likely to give mysterious results, especially with mistaken
arguments.  I understand that the current flatten for 1.2 beta doesn't
do this -- I'm just throwing in another suggestion after playing with
it for a while.

Here's my suggestion:

(defn fl1 faster flatten [coll]
  (letfn [(flcoll [coll]
 (lazy-seq
  (when-let [c (seq coll)]
(let [x (first c)
  nxt (flcoll (next c))]
  (if (sequential? x)
(concat (flcoll x) nxt)
(cons x nxt))]
(if (sequential? coll) (flcoll coll) coll)))

-- 
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: faster flatten?

2010-07-14 Thread Cam
I definitely like this version a little better. If you change the else
of the if to be just (list), it returns the empty list just as core/
flatten does. Mind if I update the ticket with this patch?

On Jul 14, 1:56 pm, miner stevemi...@gmail.com wrote:
 I think it's worthwhile to have a faster flatten even if it doesn't
 look as elegant as the current implementation.  You could do a bit of
 refactoring and save yourself a call to sequential? since the
 recursive calls are guaranteed to have seqs (as a result of next).

 Also, I'd prefer flatten to return the argument if it isn't
 sequential? so for example, (flatten 10) == 10.  I think it would be
 less likely to give mysterious results, especially with mistaken
 arguments.  I understand that the current flatten for 1.2 beta doesn't
 do this -- I'm just throwing in another suggestion after playing with
 it for a while.

 Here's my suggestion:

 (defn fl1 faster flatten [coll]
   (letfn [(flcoll [coll]
                  (lazy-seq
                   (when-let [c (seq coll)]
                     (let [x (first c)
                           nxt (flcoll (next c))]
                       (if (sequential? x)
                         (concat (flcoll x) nxt)
                         (cons x nxt))]
     (if (sequential? coll) (flcoll coll) coll)))

-- 
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: faster flatten?

2010-07-14 Thread Steve Miner

On Jul 14, 2010, at 2:40 PM, Cam wrote:

 I definitely like this version a little better. If you change the else
 of the if to be just (list), it returns the empty list just as core/
 flatten does. Mind if I update the ticket with this patch?

It's all yours.  Really, just a slight change from your code anyway.

I wonder about the call to next.  I'm thinking it should be rest instead.  (See 
http://clojure.org/lazy)

I definitely don't like the way (flatten 10)  and (flatten {:a 1 :b 2}) return 
the empty list (in 1.2 beta).  I think these are accidents, and I worry that 
they will obscure higher-level bugs.

My preference is to return the arg if it's not sequential? as I believe it will 
provide a more useful result at no extra cost.  In that case, the argument to 
flatten was probably a mistake, and it's better if the value shows up somewhere 
rather than being mysteriously swallowed.  On the other hand, it might make 
sense to return (list arg) on the theory that flatten should always return a 
seq.  I could live with 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: faster flatten?

2010-07-13 Thread Stuart Halloway
Hi Cam,

Your tests aren't testing the interesting part without a doall. 

That said, my quick tests with doall show your approach faring even better. :-) 
Also, I think what my-flatten does with Java arrays is intuitive (and the 
current flatten not so much).

A patch that preserves the semantics of the existing flatten (except for 
working with Java arrays) would be welcome.

Thanks!
Stu

 Another flatten thread! Sorry..
 
 Hello all, before I realized there was a flatten in the master branch
 (and before I looked at contrib) I wrote this pretty standard code:
 
 (defn my-flatten [coll]
 (lazy-seq
   (when-let [coll (seq coll)]
 (let [x (first coll)]
   (if (sequential? x)
 (concat (my-flatten x) (my-flatten (next coll)))
 (cons x (my-flatten (next coll
 
 (There's very similar versions on the boards. I'm not claiming this is
 anything amazing or unique.)
 
 It's not as elegant as what's in core, but in my micro benchmarks (ran
 on my laptop; 2.26 core 2 and 4gb ram) it seems to perform a bit
 better, _especially_ in the already flattened case. It behaves just
 like core/flatten except that it doesn't return an empty list when
 passed a map or set, it just returns whatever you gave it but with the
 top level converted to a seq. I'm pretty much a clojure noob, so are
 there any hidden detractors of this implementation as opposed to the
 version introduced in 1.2?
 
 Also, quick note, if you swap the call to sequential? with seqable?
 from contrib/core, it flattens maps and sets like you'd expect as
 well.
 Here is how it looks
 user= (my-flatten #{1 {2 3} 4 [5 6 7 #{8 {9 10}}]})
 (1 2 3 4 5 6 7 9 10 8)
 
 And for the micro-benchmarks (using sequential?):
 
 user= (time (dotimes [_ 1e7] (flatten [1 2 3 4])))
 Elapsed time: 14,661.592 msecs
 nil
 
 user= (time (dotimes [_ 1e7] (my-flatten [1 2 3 4])))
 Elapsed time: 922.268 msecs
 nil
 
 user= (time (dotimes [_ 1e7] (flatten [1 [2 [3 [4 [5 [6 [7 [8]
 [[[9]]] 10 [11] 12 [13 14 [15])))
 Elapsed time: 18,147.959 msecs
 nil
 
 user= (time (dotimes [_ 1e7] (my-flatten [1 [2 [3 [4 [5 [6 [7 [8]
 [[[9]]] 10 [11] 12 [13 14 [15])))
 Elapsed time: 6,088.914 msecs
 nil
 
 user= (time (dotimes [_ 1e7] (flatten [[1 2 3 4 5 6 7 8 9 10]])))
 Elapsed time: 11,696.693 msecs
 nil
 
 user= (time (dotimes [_ 1e7] (my-flatten [[1 2 3 4 5 6 7 8 9 10]])))
 Elapsed time: 1,533.983 msecs
 nil
 
 Thoughts?
 
 -- 
 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

-- 
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: faster flatten?

2010-07-13 Thread Cam
Hi Stuart,

Thanks for checking that out for me! Sorry for not realizing in the
first place.

I of course would be happy to submit a patch. Should I submit that
here or over on the assembla page?

On Jul 13, 9:10 am, Stuart Halloway stuart.hallo...@gmail.com wrote:
 Hi Cam,

 Your tests aren't testing the interesting part without a doall.

 That said, my quick tests with doall show your approach faring even better. 
 :-) Also, I think what my-flatten does with Java arrays is intuitive (and the 
 current flatten not so much).

 A patch that preserves the semantics of the existing flatten (except for 
 working with Java arrays) would be welcome.

 Thanks!
 Stu



  Another flatten thread! Sorry..

  Hello all, before I realized there was a flatten in the master branch
  (and before I looked at contrib) I wrote this pretty standard code:

  (defn my-flatten [coll]
  (lazy-seq
    (when-let [coll (seq coll)]
      (let [x (first coll)]
        (if (sequential? x)
          (concat (my-flatten x) (my-flatten (next coll)))
          (cons x (my-flatten (next coll

  (There's very similar versions on the boards. I'm not claiming this is
  anything amazing or unique.)

  It's not as elegant as what's in core, but in my micro benchmarks (ran
  on my laptop; 2.26 core 2 and 4gb ram) it seems to perform a bit
  better, _especially_ in the already flattened case. It behaves just
  like core/flatten except that it doesn't return an empty list when
  passed a map or set, it just returns whatever you gave it but with the
  top level converted to a seq. I'm pretty much a clojure noob, so are
  there any hidden detractors of this implementation as opposed to the
  version introduced in 1.2?

  Also, quick note, if you swap the call to sequential? with seqable?
  from contrib/core, it flattens maps and sets like you'd expect as
  well.
  Here is how it looks
  user= (my-flatten #{1 {2 3} 4 [5 6 7 #{8 {9 10}}]})
  (1 2 3 4 5 6 7 9 10 8)

  And for the micro-benchmarks (using sequential?):

  user= (time (dotimes [_ 1e7] (flatten [1 2 3 4])))
  Elapsed time: 14,661.592 msecs
  nil

  user= (time (dotimes [_ 1e7] (my-flatten [1 2 3 4])))
  Elapsed time: 922.268 msecs
  nil

  user= (time (dotimes [_ 1e7] (flatten [1 [2 [3 [4 [5 [6 [7 [8]
  [[[9]]] 10 [11] 12 [13 14 [15])))
  Elapsed time: 18,147.959 msecs
  nil

  user= (time (dotimes [_ 1e7] (my-flatten [1 [2 [3 [4 [5 [6 [7 [8]
  [[[9]]] 10 [11] 12 [13 14 [15])))
  Elapsed time: 6,088.914 msecs
  nil

  user= (time (dotimes [_ 1e7] (flatten [[1 2 3 4 5 6 7 8 9 10]])))
  Elapsed time: 11,696.693 msecs
  nil

  user= (time (dotimes [_ 1e7] (my-flatten [[1 2 3 4 5 6 7 8 9 10]])))
  Elapsed time: 1,533.983 msecs
  nil

  Thoughts?

  --
  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

-- 
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: faster flatten?

2010-07-13 Thread Stuart Halloway
Hi Cam,

The full instructions for joining the team and then submitting a patch are at 
[1] an [2], but in short:

* send in a CA
* join the Assembla space under you real name
* post a patch there linking to this thread

Thanks!
Stu

[1] http://clojure.org/contributing
[2] http://clojure.org/patches

 Hi Stuart,
 
 Thanks for checking that out for me! Sorry for not realizing in the
 first place.
 
 I of course would be happy to submit a patch. Should I submit that
 here or over on the assembla page?
 
 On Jul 13, 9:10 am, Stuart Halloway stuart.hallo...@gmail.com wrote:
 Hi Cam,
 
 Your tests aren't testing the interesting part without a doall.
 
 That said, my quick tests with doall show your approach faring even better. 
 :-) Also, I think what my-flatten does with Java arrays is intuitive (and 
 the current flatten not so much).
 
 A patch that preserves the semantics of the existing flatten (except for 
 working with Java arrays) would be welcome.
 
 Thanks!
 Stu
 
 
 
 Another flatten thread! Sorry..
 
 Hello all, before I realized there was a flatten in the master branch
 (and before I looked at contrib) I wrote this pretty standard code:
 
 (defn my-flatten [coll]
 (lazy-seq
   (when-let [coll (seq coll)]
 (let [x (first coll)]
   (if (sequential? x)
 (concat (my-flatten x) (my-flatten (next coll)))
 (cons x (my-flatten (next coll
 
 (There's very similar versions on the boards. I'm not claiming this is
 anything amazing or unique.)
 
 It's not as elegant as what's in core, but in my micro benchmarks (ran
 on my laptop; 2.26 core 2 and 4gb ram) it seems to perform a bit
 better, _especially_ in the already flattened case. It behaves just
 like core/flatten except that it doesn't return an empty list when
 passed a map or set, it just returns whatever you gave it but with the
 top level converted to a seq. I'm pretty much a clojure noob, so are
 there any hidden detractors of this implementation as opposed to the
 version introduced in 1.2?
 
 Also, quick note, if you swap the call to sequential? with seqable?
 from contrib/core, it flattens maps and sets like you'd expect as
 well.
 Here is how it looks
 user= (my-flatten #{1 {2 3} 4 [5 6 7 #{8 {9 10}}]})
 (1 2 3 4 5 6 7 9 10 8)
 
 And for the micro-benchmarks (using sequential?):
 
 user= (time (dotimes [_ 1e7] (flatten [1 2 3 4])))
 Elapsed time: 14,661.592 msecs
 nil
 
 user= (time (dotimes [_ 1e7] (my-flatten [1 2 3 4])))
 Elapsed time: 922.268 msecs
 nil
 
 user= (time (dotimes [_ 1e7] (flatten [1 [2 [3 [4 [5 [6 [7 [8]
 [[[9]]] 10 [11] 12 [13 14 [15])))
 Elapsed time: 18,147.959 msecs
 nil
 
 user= (time (dotimes [_ 1e7] (my-flatten [1 [2 [3 [4 [5 [6 [7 [8]
 [[[9]]] 10 [11] 12 [13 14 [15])))
 Elapsed time: 6,088.914 msecs
 nil
 
 user= (time (dotimes [_ 1e7] (flatten [[1 2 3 4 5 6 7 8 9 10]])))
 Elapsed time: 11,696.693 msecs
 nil
 
 user= (time (dotimes [_ 1e7] (my-flatten [[1 2 3 4 5 6 7 8 9 10]])))
 Elapsed time: 1,533.983 msecs
 nil
 
 Thoughts?
 
 --
 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
 
 -- 
 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

-- 
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: faster flatten?

2010-07-13 Thread Cam
Hi again, I modified my-flatten to return the empty list for sets and
maps as core/flatten does. It doesn't seem to handle Arrays anymore
though. I'm assuming it's because ArrayList and (int-array ...) don't
implement Sequential. None the less should I still submit this
modified version that behaves just like core/flatten?

(defn my-flatten
  [coll]
  (lazy-seq
(when-let [coll (if (sequential? coll) (seq coll))]
  (let [x (first coll)]
(if (sequential? x)
  (concat (my-flatten x) (my-flatten (next coll)))
  (cons x (my-flatten (next coll

Might it be worth promoting seqable? to core? In that case flatten
would handle pretty much everything you could throw at it like you'd
expect. I don't speak for everyone but when I saw sequential? I
assumed it would have the semantics that seqable? does.


On Jul 13, 11:04 am, Cam dlocpuw...@gmail.com wrote:
 Hi Stuart,

 Thanks for checking that out for me! Sorry for not realizing in the
 first place.

 I of course would be happy to submit a patch. Should I submit that
 here or over on the assembla page?

 On Jul 13, 9:10 am, Stuart Halloway stuart.hallo...@gmail.com wrote:



  Hi Cam,

  Your tests aren't testing the interesting part without a doall.

  That said, my quick tests with doall show your approach faring even better. 
  :-) Also, I think what my-flatten does with Java arrays is intuitive (and 
  the current flatten not so much).

  A patch that preserves the semantics of the existing flatten (except for 
  working with Java arrays) would be welcome.

  Thanks!
  Stu

   Another flatten thread! Sorry..

   Hello all, before I realized there was a flatten in the master branch
   (and before I looked at contrib) I wrote this pretty standard code:

   (defn my-flatten [coll]
   (lazy-seq
     (when-let [coll (seq coll)]
       (let [x (first coll)]
         (if (sequential? x)
           (concat (my-flatten x) (my-flatten (next coll)))
           (cons x (my-flatten (next coll

   (There's very similar versions on the boards. I'm not claiming this is
   anything amazing or unique.)

   It's not as elegant as what's in core, but in my micro benchmarks (ran
   on my laptop; 2.26 core 2 and 4gb ram) it seems to perform a bit
   better, _especially_ in the already flattened case. It behaves just
   like core/flatten except that it doesn't return an empty list when
   passed a map or set, it just returns whatever you gave it but with the
   top level converted to a seq. I'm pretty much a clojure noob, so are
   there any hidden detractors of this implementation as opposed to the
   version introduced in 1.2?

   Also, quick note, if you swap the call to sequential? with seqable?
   from contrib/core, it flattens maps and sets like you'd expect as
   well.
   Here is how it looks
   user= (my-flatten #{1 {2 3} 4 [5 6 7 #{8 {9 10}}]})
   (1 2 3 4 5 6 7 9 10 8)

   And for the micro-benchmarks (using sequential?):

   user= (time (dotimes [_ 1e7] (flatten [1 2 3 4])))
   Elapsed time: 14,661.592 msecs
   nil

   user= (time (dotimes [_ 1e7] (my-flatten [1 2 3 4])))
   Elapsed time: 922.268 msecs
   nil

   user= (time (dotimes [_ 1e7] (flatten [1 [2 [3 [4 [5 [6 [7 [8]
   [[[9]]] 10 [11] 12 [13 14 [15])))
   Elapsed time: 18,147.959 msecs
   nil

   user= (time (dotimes [_ 1e7] (my-flatten [1 [2 [3 [4 [5 [6 [7 [8]
   [[[9]]] 10 [11] 12 [13 14 [15])))
   Elapsed time: 6,088.914 msecs
   nil

   user= (time (dotimes [_ 1e7] (flatten [[1 2 3 4 5 6 7 8 9 10]])))
   Elapsed time: 11,696.693 msecs
   nil

   user= (time (dotimes [_ 1e7] (my-flatten [[1 2 3 4 5 6 7 8 9 10]])))
   Elapsed time: 1,533.983 msecs
   nil

   Thoughts?

   --
   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

-- 
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: faster flatten?

2010-07-13 Thread Stuart Halloway
Hi Cam,

Please submit the modified version, and, if you want, create a separate ticket 
for seqable?. I would like to review the latter separately.

Stu

 Hi again, I modified my-flatten to return the empty list for sets and
 maps as core/flatten does. It doesn't seem to handle Arrays anymore
 though. I'm assuming it's because ArrayList and (int-array ...) don't
 implement Sequential. None the less should I still submit this
 modified version that behaves just like core/flatten?
 
 (defn my-flatten
  [coll]
  (lazy-seq
(when-let [coll (if (sequential? coll) (seq coll))]
  (let [x (first coll)]
(if (sequential? x)
  (concat (my-flatten x) (my-flatten (next coll)))
  (cons x (my-flatten (next coll
 
 Might it be worth promoting seqable? to core? In that case flatten
 would handle pretty much everything you could throw at it like you'd
 expect. I don't speak for everyone but when I saw sequential? I
 assumed it would have the semantics that seqable? does.
 
 
 On Jul 13, 11:04 am, Cam dlocpuw...@gmail.com wrote:
 Hi Stuart,
 
 Thanks for checking that out for me! Sorry for not realizing in the
 first place.
 
 I of course would be happy to submit a patch. Should I submit that
 here or over on the assembla page?
 
 On Jul 13, 9:10 am, Stuart Halloway stuart.hallo...@gmail.com wrote:
 
 
 
 Hi Cam,
 
 Your tests aren't testing the interesting part without a doall.
 
 That said, my quick tests with doall show your approach faring even better. 
 :-) Also, I think what my-flatten does with Java arrays is intuitive (and 
 the current flatten not so much).
 
 A patch that preserves the semantics of the existing flatten (except for 
 working with Java arrays) would be welcome.
 
 Thanks!
 Stu
 
 Another flatten thread! Sorry..
 
 Hello all, before I realized there was a flatten in the master branch
 (and before I looked at contrib) I wrote this pretty standard code:
 
 (defn my-flatten [coll]
 (lazy-seq
   (when-let [coll (seq coll)]
 (let [x (first coll)]
   (if (sequential? x)
 (concat (my-flatten x) (my-flatten (next coll)))
 (cons x (my-flatten (next coll
 
 (There's very similar versions on the boards. I'm not claiming this is
 anything amazing or unique.)
 
 It's not as elegant as what's in core, but in my micro benchmarks (ran
 on my laptop; 2.26 core 2 and 4gb ram) it seems to perform a bit
 better, _especially_ in the already flattened case. It behaves just
 like core/flatten except that it doesn't return an empty list when
 passed a map or set, it just returns whatever you gave it but with the
 top level converted to a seq. I'm pretty much a clojure noob, so are
 there any hidden detractors of this implementation as opposed to the
 version introduced in 1.2?
 
 Also, quick note, if you swap the call to sequential? with seqable?
 from contrib/core, it flattens maps and sets like you'd expect as
 well.
 Here is how it looks
 user= (my-flatten #{1 {2 3} 4 [5 6 7 #{8 {9 10}}]})
 (1 2 3 4 5 6 7 9 10 8)
 
 And for the micro-benchmarks (using sequential?):
 
 user= (time (dotimes [_ 1e7] (flatten [1 2 3 4])))
 Elapsed time: 14,661.592 msecs
 nil
 
 user= (time (dotimes [_ 1e7] (my-flatten [1 2 3 4])))
 Elapsed time: 922.268 msecs
 nil
 
 user= (time (dotimes [_ 1e7] (flatten [1 [2 [3 [4 [5 [6 [7 [8]
 [[[9]]] 10 [11] 12 [13 14 [15])))
 Elapsed time: 18,147.959 msecs
 nil
 
 user= (time (dotimes [_ 1e7] (my-flatten [1 [2 [3 [4 [5 [6 [7 [8]
 [[[9]]] 10 [11] 12 [13 14 [15])))
 Elapsed time: 6,088.914 msecs
 nil
 
 user= (time (dotimes [_ 1e7] (flatten [[1 2 3 4 5 6 7 8 9 10]])))
 Elapsed time: 11,696.693 msecs
 nil
 
 user= (time (dotimes [_ 1e7] (my-flatten [[1 2 3 4 5 6 7 8 9 10]])))
 Elapsed time: 1,533.983 msecs
 nil
 
 Thoughts?
 
 --
 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
 
 -- 
 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

-- 
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

Re: faster flatten?

2010-07-13 Thread Cam
OK, all submitted. The tickets are up for discussion at

http://www.assembla.com/spaces/clojure/support/tickets/400-a-faster-flatten
http://www.assembla.com/spaces/clojure/support/tickets/401-promote--seqable---from-contrib-

I will mail my CA in tomorrow morning.

Thanks Stu and Mark!

On Jul 13, 11:57 am, Stuart Halloway stuart.hallo...@gmail.com
wrote:
 Hi Cam,

 Please submit the modified version, and, if you want, create a separate 
 ticket for seqable?. I would like to review the latter separately.

 Stu



  Hi again, I modified my-flatten to return the empty list for sets and
  maps as core/flatten does. It doesn't seem to handle Arrays anymore
  though. I'm assuming it's because ArrayList and (int-array ...) don't
  implement Sequential. None the less should I still submit this
  modified version that behaves just like core/flatten?

  (defn my-flatten
   [coll]
   (lazy-seq
     (when-let [coll (if (sequential? coll) (seq coll))]
       (let [x (first coll)]
         (if (sequential? x)
           (concat (my-flatten x) (my-flatten (next coll)))
           (cons x (my-flatten (next coll

  Might it be worth promoting seqable? to core? In that case flatten
  would handle pretty much everything you could throw at it like you'd
  expect. I don't speak for everyone but when I saw sequential? I
  assumed it would have the semantics that seqable? does.

  On Jul 13, 11:04 am, Cam dlocpuw...@gmail.com wrote:
  Hi Stuart,

  Thanks for checking that out for me! Sorry for not realizing in the
  first place.

  I of course would be happy to submit a patch. Should I submit that
  here or over on the assembla page?

  On Jul 13, 9:10 am, Stuart Halloway stuart.hallo...@gmail.com wrote:

  Hi Cam,

  Your tests aren't testing the interesting part without a doall.

  That said, my quick tests with doall show your approach faring even 
  better. :-) Also, I think what my-flatten does with Java arrays is 
  intuitive (and the current flatten not so much).

  A patch that preserves the semantics of the existing flatten (except for 
  working with Java arrays) would be welcome.

  Thanks!
  Stu

  Another flatten thread! Sorry..

  Hello all, before I realized there was a flatten in the master branch
  (and before I looked at contrib) I wrote this pretty standard code:

  (defn my-flatten [coll]
  (lazy-seq
    (when-let [coll (seq coll)]
      (let [x (first coll)]
        (if (sequential? x)
          (concat (my-flatten x) (my-flatten (next coll)))
          (cons x (my-flatten (next coll

  (There's very similar versions on the boards. I'm not claiming this is
  anything amazing or unique.)

  It's not as elegant as what's in core, but in my micro benchmarks (ran
  on my laptop; 2.26 core 2 and 4gb ram) it seems to perform a bit
  better, _especially_ in the already flattened case. It behaves just
  like core/flatten except that it doesn't return an empty list when
  passed a map or set, it just returns whatever you gave it but with the
  top level converted to a seq. I'm pretty much a clojure noob, so are
  there any hidden detractors of this implementation as opposed to the
  version introduced in 1.2?

  Also, quick note, if you swap the call to sequential? with seqable?
  from contrib/core, it flattens maps and sets like you'd expect as
  well.
  Here is how it looks
  user= (my-flatten #{1 {2 3} 4 [5 6 7 #{8 {9 10}}]})
  (1 2 3 4 5 6 7 9 10 8)

  And for the micro-benchmarks (using sequential?):

  user= (time (dotimes [_ 1e7] (flatten [1 2 3 4])))
  Elapsed time: 14,661.592 msecs
  nil

  user= (time (dotimes [_ 1e7] (my-flatten [1 2 3 4])))
  Elapsed time: 922.268 msecs
  nil

  user= (time (dotimes [_ 1e7] (flatten [1 [2 [3 [4 [5 [6 [7 [8]
  [[[9]]] 10 [11] 12 [13 14 [15])))
  Elapsed time: 18,147.959 msecs
  nil

  user= (time (dotimes [_ 1e7] (my-flatten [1 [2 [3 [4 [5 [6 [7 [8]
  [[[9]]] 10 [11] 12 [13 14 [15])))
  Elapsed time: 6,088.914 msecs
  nil

  user= (time (dotimes [_ 1e7] (flatten [[1 2 3 4 5 6 7 8 9 10]])))
  Elapsed time: 11,696.693 msecs
  nil

  user= (time (dotimes [_ 1e7] (my-flatten [[1 2 3 4 5 6 7 8 9 10]])))
  Elapsed time: 1,533.983 msecs
  nil

  Thoughts?

  --
  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

  --
  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

faster flatten?

2010-07-12 Thread Cam
Another flatten thread! Sorry..

Hello all, before I realized there was a flatten in the master branch
(and before I looked at contrib) I wrote this pretty standard code:

(defn my-flatten [coll]
 (lazy-seq
   (when-let [coll (seq coll)]
 (let [x (first coll)]
   (if (sequential? x)
 (concat (my-flatten x) (my-flatten (next coll)))
 (cons x (my-flatten (next coll

(There's very similar versions on the boards. I'm not claiming this is
anything amazing or unique.)

It's not as elegant as what's in core, but in my micro benchmarks (ran
on my laptop; 2.26 core 2 and 4gb ram) it seems to perform a bit
better, _especially_ in the already flattened case. It behaves just
like core/flatten except that it doesn't return an empty list when
passed a map or set, it just returns whatever you gave it but with the
top level converted to a seq. I'm pretty much a clojure noob, so are
there any hidden detractors of this implementation as opposed to the
version introduced in 1.2?

Also, quick note, if you swap the call to sequential? with seqable?
from contrib/core, it flattens maps and sets like you'd expect as
well.
Here is how it looks
user= (my-flatten #{1 {2 3} 4 [5 6 7 #{8 {9 10}}]})
(1 2 3 4 5 6 7 9 10 8)

And for the micro-benchmarks (using sequential?):

user= (time (dotimes [_ 1e7] (flatten [1 2 3 4])))
Elapsed time: 14,661.592 msecs
nil

user= (time (dotimes [_ 1e7] (my-flatten [1 2 3 4])))
Elapsed time: 922.268 msecs
nil

user= (time (dotimes [_ 1e7] (flatten [1 [2 [3 [4 [5 [6 [7 [8]
[[[9]]] 10 [11] 12 [13 14 [15])))
Elapsed time: 18,147.959 msecs
nil

user= (time (dotimes [_ 1e7] (my-flatten [1 [2 [3 [4 [5 [6 [7 [8]
[[[9]]] 10 [11] 12 [13 14 [15])))
Elapsed time: 6,088.914 msecs
nil

user= (time (dotimes [_ 1e7] (flatten [[1 2 3 4 5 6 7 8 9 10]])))
Elapsed time: 11,696.693 msecs
nil

user= (time (dotimes [_ 1e7] (my-flatten [[1 2 3 4 5 6 7 8 9 10]])))
Elapsed time: 1,533.983 msecs
nil

Thoughts?

-- 
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: faster flatten?

2010-07-12 Thread Mark Engelberg
Unless you wrap a doall around the calls to flatten and my-flatten,
you're not really timing anything relevant.

-- 
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: A better flatten

2009-09-03 Thread Meikel Brandmeyer



On Sep 3, 1:13 am, Sudish Joseph sud...@gmail.com wrote:

 (defn flatten-2 [lst]
   (lazy-seq
     (if-let [x (first lst)]
       (let [xs (rest lst)]
         (if (seq? x)
           (concat (flatten-2 x) (flatten-2 xs))
           (cons x (flatten-2 xs)))

This version is broken:
user= (flatten-2 '(:a (:b :c) false :d :e))
(:a :b :c)

Never check with first for nil. Always check explicitely with seq!

(defn flatten-3
  [s]
  (lazy-seq
(when-let [s (seq s)]
  (let [fst (first s)]
(if (seq? fst)
  (concat (flatten-3 fst) (flatten-3 (rest s)))
  (cons fst (flatten-3 (rest s

user= (flatten-3 '(:a (:b :c) false :d :e))
(:a :b :c false :d :e)

Sincerely
Meikel

--~--~-~--~~~---~--~~
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: A better flatten

2009-09-02 Thread Sean Devlin

It's in c.c.seq-utils

You can look up stuff here:

http://richhickey.github.com/clojure-contrib/api-index.html

On Sep 2, 4:12 pm, tmountain tinymount...@gmail.com wrote:
 I believe the flatten in contrib is defined as follows. I can't
 remember which module I found it in.

 (defn flatten
   Takes any nested combination of sequential things (lists, vectors,
   etc.) and returns their contents as a single, flat sequence.
   (flatten nil) returns nil.
   [x]
   (filter (complement sequential?)
           (rest (tree-seq sequential? seq x

 -Travis

 On Sep 2, 3:33 pm, Krukow karl.kru...@gmail.com wrote:

  Hello,
  At some point I needed at flatten function taking a list of atomic
  elements or nested lists, and producting a flat list of only atomic
  elements (in the same order). It should be lazy.

  This is what I came up with. Can anyone see a more elegant solution (I
  feel I am working low-level somehow).

  user (defn flatten [lst]
          (lazy-seq
            (if (empty? lst) lst
                (let [[x  xs] lst]
                  (if (list? x)
                    (concat (flatten x) (flatten xs))
                    (cons x (flatten xs)))
  #'user/flatten
  user (flatten '(1 2 3 4))
  (1 2 3 4)
  user (flatten '((1 2) (3) 4))
  (1 2 3 4)
  user (flatten '(((1) 2) (3) 4))
  (1 2 3 4)
  user

  /Karl
--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



A better flatten

2009-09-02 Thread Krukow

Hello,
At some point I needed at flatten function taking a list of atomic
elements or nested lists, and producting a flat list of only atomic
elements (in the same order). It should be lazy.

This is what I came up with. Can anyone see a more elegant solution (I
feel I am working low-level somehow).

user (defn flatten [lst]
(lazy-seq
  (if (empty? lst) lst
  (let [[x  xs] lst]
(if (list? x)
  (concat (flatten x) (flatten xs))
  (cons x (flatten xs)))
#'user/flatten
user (flatten '(1 2 3 4))
(1 2 3 4)
user (flatten '((1 2) (3) 4))
(1 2 3 4)
user (flatten '(((1) 2) (3) 4))
(1 2 3 4)
user

/Karl
--~--~-~--~~~---~--~~
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: A better flatten

2009-09-02 Thread Sudish Joseph

Hi Karl,

The other solutions seem higher level, but it's worth noting that
destructuring -- (let [[x  xs] lst] ...) -- uses next and is therefore
not fully lazy in that you will peek ahead by one into the lazy
sequence, so to speak.  You have to use explicit first / rest to get
that:

;; with destructuring
(defn flatten [lst]
  (lazy-seq
(if (empty? lst) lst
(let [[x  xs] lst]
  (if (list? x)
(concat (flatten x) (flatten xs))
(cons x (flatten xs)))

;; explicit first / rest
(defn flatten-2 [lst]
  (lazy-seq
(if-let [x (first lst)]
  (let [xs (rest lst)]
(if (seq? x)
  (concat (flatten-2 x) (flatten-2 xs))
  (cons x (flatten-2 xs)))

;; returns a fresh, unevaluated, lazy seq each time
(defn lazy-integers []
  (map #(do (print (str [ % ] )) %)
   (iterate inc 0)))

Then:

user (take 5 (flatten (lazy-integers)))
([0] [1] [2] 0 [3] 1 [4] 2 [5] 3 4)

user (take 5 (flatten-2 (lazy-integers)))
([0] [1] 0 [2] 1 [3] 2 [4] 3 4)

So, flatten-2 never looks at the 6th element, 5, when it returns the
first 5.  It's fully lazy in that it only evaluates the elements needed
for the result.

Of course, this is not a problem unless the lazy seq contains
computationally intensive or has side effects that need to be accounted
for in other ways.

-Sudish

--~--~-~--~~~---~--~~
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: A better flatten

2009-09-02 Thread Krukow


On Sep 3, 1:13 am, Sudish Joseph sud...@gmail.com wrote:
 The other solutions seem higher level, but it's worth noting that
 destructuring -- (let [[x  xs] lst] ...) -- uses next and is therefore
 not fully lazy in that you will peek ahead by one into the lazy
 sequence, so to speak.  You have to use explicit first / rest to get
 that:
[snip...]

Thanks everyone. I like the contrib version particularly.

Regarding eagerness of let: now that you mention it I recall that from
a recent thread.

http://groups.google.com/group/clojure/browse_frm/thread/32ff3ca7e2649867/ba0aa1edf7cfaeb1?hl=en

I think '' would be a nice addition.

/Karl
--~--~-~--~~~---~--~~
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: seq-utils testing reveals potential flatten bugs

2009-08-08 Thread Meikel Brandmeyer

Hi,

Am 08.08.2009 um 07:36 schrieb Sean Devlin:


In my opinion, flatten to behave more like this:

http://gist.github.com/164291


May I ask a stupid question?

What is the use of this case:

[:a 1 2 :b 3] {:a [1 2] :b 3}

Wouldn't it be more useful to flatten
only depending on the outermost type?

[:a [1 2] :b 3] {:a [1 2] :b 3}
[:a :b {:foo :bar}] #{#{:a :b} #{{:foo :bar}}}

Sincerely
Meikel



smime.p7s
Description: S/MIME cryptographic signature


Re: seq-utils testing reveals potential flatten bugs

2009-08-08 Thread Sean Devlin

My thought we to use the test cases as a specification for the desired
behavior.

1.  Assume that the following case is desired behavior

  [:a 1 2 :b 3] [[:a [1 2]] [:b 3]]

My thought was that If it's a seq, flatten it. That lead me to
develop the test case above.  Here's how it works explicitly.

  user= (seq {:a [1 2] :b 3})
  ([:a [1 2]] [:b 3])

Therefore...

  user=(flatten (seq {:a [1 2] :b 3}))
  [:a 1 2 :b 3]

Is this the right specification, though?  That's the question for this
thread.

Sean


On Aug 8, 6:11 am, Meikel Brandmeyer m...@kotka.de wrote:
 Hi,

 Am 08.08.2009 um 07:36 schrieb Sean Devlin:

  In my opinion, flatten to behave more like this:

 http://gist.github.com/164291

 May I ask a stupid question?

 What is the use of this case:

          [:a 1 2 :b 3] {:a [1 2] :b 3}

 Wouldn't it be more useful to flatten
 only depending on the outermost type?

          [:a [1 2] :b 3] {:a [1 2] :b 3}
          [:a :b {:foo :bar}] #{#{:a :b} #{{:foo :bar}}}

 Sincerely
 Meikel

  smime.p7s
 2KViewDownload
--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



seq-utils testing reveals potential flatten bugs

2009-08-07 Thread Sean Devlin

See Assembla ticket 13 in for clojure contrib to view the diff
containing the test cases

I just finished writing tests for the following functions in seq-
utils:

flatten
separate
includes?
indexed
group-by
partition-by
frequencies
reductions
rotations
partition-all
shuffle (invariants)
rand-elt (invariants)
find-first

As best I can tell, all of these functions except flatten behave as
they should.  There were no surprises with them.

flatten is a different story.

I wrote my test cases to deliberately make flatten pass.  This way it
can be used as a regression testing tool.  That being said, I found
several behaviors with flatten that I think are bugs.  Check the
flatten test function at the beginning of the file for examples.  The
executive summary is

1.  flattening a set at the top level always returns an empty seq.
Wrapping the set in a seq call enables normal behavior

2.  flattening a map at the top level always returns an empty seq.
Wrapping the map in a seq call enables normal behavior

3.  flattening a vector containing a set does not recursively enter
the set.

4.  flattening a vector containing a map does not recursively enter
the map.

5.  flattening nil returns an empty seq.  The doc string explicitly
states that (flatten nil) should return nil.

In my opinion, flatten to behave more like this:

http://gist.github.com/164291

It seems to me that the differnce is the sequential? call in
flatten.

One way to reconcile this is to have a proper seqable? function, like
the one specified in clojure.contrib.core.seqable? (recently discussed
here: 
http://groups.google.com/group/clojure/browse_thread/thread/9dbaff59e8de9a8a/7db470140505a92d
).  There would still be some minor tweaking required, but I think
this will enable maps and sets to behave properly.

Hope this helps,
Sean


--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



flatten tools

2009-07-10 Thread kyle smith

I wrote these and thought they might be useful.  Feel free to add them
to clojure.contrib.seq-utils

(defn flatten-n [n coll]
  Like flatten, but only goes n levels deep.
  (if (= n 0)
coll
(recur (dec n) (apply concat (map #(if (sequential? %) % (list %))
coll)

(defn- unflatten* [tree coll]
  (loop [val-tree []
 new-tree tree
 new-coll coll]
(if (nil? (first new-tree))
  [val-tree new-coll]
  (if (sequential? (first new-tree))
(let [[a b] (unflatten* (first new-tree) new-coll)]
  (recur (conj val-tree a) (next new-tree) b))
(recur (conj val-tree (first new-coll)) (next new-tree) (next new-
coll))

(defn unflatten [tree coll]
  Returns a new tree with the same shape as tree containing the
elements of coll.
   coll must be of length #leaves of tree
  (first (unflatten* tree coll)))


user (unflatten [[1] [2 3] 4 [5 [6]] 7] '[a b c d e f g])
[[a] [b c] d [e [f]] g]
--~--~-~--~~~---~--~~
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: How to flatten a coll only 1 level deep?

2009-04-09 Thread Paul Drummond

2009/4/9 Chouser chou...@gmail.com:
 (defn flat1 [coll]
  (mapcat #(if (coll? %) % [%]) coll))

Ah, I see.  So for each item, if its already a collection we leave it
alone and if not we make a vector of one item, then at the end we use
mapcat to concatinate all the top-level items into one list.

Excellent - thank you!

Paul.
-- 
Iode Software Ltd, registered in England No. 6299803.

Registered Office Address: 12 Sancroft Drive, Houghton-le-Spring, Tyne
 Wear, DH5 8NE.

This message is intended only for the use of the person(s) (the
intended recipient(s)) to whom it is addressed. It may contain
information which is privileged and confidential within the meaning of
applicable law. If you are not the intended recipient, please contact
the sender as soon as possible. The views expressed in this
communication may not necessarily be the views held by The Company.

--~--~-~--~~~---~--~~
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
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
-~--~~~~--~~--~--~---



How to flatten a coll only 1 level deep?

2009-04-08 Thread Paul Drummond

I am looking for something similar to flatten (in contrib.seq-utils)
but the function will only flatten one level deep:

[ 1 2 3 [4 5 [6 7] ] ] --- [ 1 2 3 4 5 [6 7] ]

I have tried combining functions in the seq library and I've studied
the code for flatten and tree-seq to look for hints but so far I can't
see the way to do this. Can anyone help?

Thanks,
Paul
-- 
Iode Software Ltd, registered in England No. 6299803.

Registered Office Address: 12 Sancroft Drive, Houghton-le-Spring, Tyne
 Wear, DH5 8NE.

This message is intended only for the use of the person(s) (the
intended recipient(s)) to whom it is addressed. It may contain
information which is privileged and confidential within the meaning of
applicable law. If you are not the intended recipient, please contact
the sender as soon as possible. The views expressed in this
communication may not necessarily be the views held by The Company.

--~--~-~--~~~---~--~~
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
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: How to flatten a coll only 1 level deep?

2009-04-08 Thread Chouser

On Wed, Apr 8, 2009 at 10:10 PM, Paul Drummond paul.drumm...@iode.co.uk wrote:

 I am looking for something similar to flatten (in contrib.seq-utils)
 but the function will only flatten one level deep:

 [ 1 2 3 [4 5 [6 7] ] ] --- [ 1 2 3 4 5 [6 7] ]

 I have tried combining functions in the seq library and I've studied
 the code for flatten and tree-seq to look for hints but so far I can't
 see the way to do this. Can anyone help?

(defn flat1 [coll]
  (mapcat #(if (coll? %) % [%]) coll))

(flat1 [ 1 2 3 [4 5 [6 7] ] ])

--Chouser

--~--~-~--~~~---~--~~
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
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: Flatten a list

2009-02-25 Thread Jeffrey Straszheim
I always end up doing (filter identity '(:fred :mary nil :sue))
(remove nil? ...) is actually more clear.  I'll try to remember that.

On Tue, Feb 24, 2009 at 10:42 PM, Timothy Pratley
timothyprat...@gmail.comwrote:


 user= (remove nil? '(:a nil nil :b :a))
 (:a :b :a)

 On Feb 25, 2:38 pm, Sean francoisdev...@gmail.com wrote:
  I've got the following list
 
  (:a nil nil :b :a)
 
  I want to call a nil-killer function, and get the following list
 
  (:a :b :a)
 
  How do I go about this?  Could someone post a quick example?
 


--~--~-~--~~~---~--~~
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
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
-~--~~~~--~~--~--~---



Flatten a list

2009-02-24 Thread Sean

I've got the following list

(:a nil nil :b :a)

I want to call a nil-killer function, and get the following list

(:a :b :a)

How do I go about this?  Could someone post a quick example?
--~--~-~--~~~---~--~~
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
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: Flatten a list

2009-02-24 Thread Kevin Downey

filter, http://clojure.org/api#filter

On Tue, Feb 24, 2009 at 7:38 PM, Sean francoisdev...@gmail.com wrote:

 I've got the following list

 (:a nil nil :b :a)

 I want to call a nil-killer function, and get the following list

 (:a :b :a)

 How do I go about this?  Could someone post a quick example?
 




-- 
And what is good, Phaedrus,
And what is not good—
Need we ask anyone to tell us these things?

--~--~-~--~~~---~--~~
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
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: Flatten a list

2009-02-24 Thread Timothy Pratley

user= (remove nil? '(:a nil nil :b :a))
(:a :b :a)

On Feb 25, 2:38 pm, Sean francoisdev...@gmail.com wrote:
 I've got the following list

 (:a nil nil :b :a)

 I want to call a nil-killer function, and get the following list

 (:a :b :a)

 How do I go about this?  Could someone post a quick example?
--~--~-~--~~~---~--~~
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
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: Flatten a list

2009-02-24 Thread Sean

Awesome!  Thanks guys!

On Feb 24, 10:42 pm, Timothy Pratley timothyprat...@gmail.com wrote:
 user= (remove nil? '(:a nil nil :b :a))
 (:a :b :a)

 On Feb 25, 2:38 pm, Sean francoisdev...@gmail.com wrote:

  I've got the following list

  (:a nil nil :b :a)

  I want to call a nil-killer function, and get the following list

  (:a :b :a)

  How do I go about this?  Could someone post a quick example?
--~--~-~--~~~---~--~~
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
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: Flatten a list

2009-02-24 Thread David Sletten


On Feb 24, 2009, at 5:42 PM, Timothy Pratley wrote:


 user= (remove nil? '(:a nil nil :b :a))
 (:a :b :a)



C'mon! Doesn't anybody do things the old-fashioned way anymore?

(defn kill-nil
   ([l] (kill-nil l '()))
   ([l result] (cond (nil? l) (reverse result)
 (nil? (first l)) (recur (rest l) result)
 true (recur (rest l) (cons (first l) result )

You young whipper snappers!

Aloha,
David Sletten

--~--~-~--~~~---~--~~
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
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: Flatten a list

2009-02-24 Thread David Sletten


On Feb 24, 2009, at 6:07 PM, David Sletten wrote:


 (defn kill-nil
([l] (kill-nil l '()))
([l result] (cond (nil? l) (reverse result)
  (nil? (first l)) (recur (rest l) result)
  true (recur (rest l) (cons (first l) result )



I forgot to ask...

In Lisp, rather than repeatedly testing for an optional argument like  
this:
(defun kill-nil (l optional (result '()))
   (cond ((endp l) (nreverse result))
 ((null (first l)) (kill-nil (rest l) result))
 (t (kill-nil (rest l) (cons (first l) result )

I would preserve the interface to the user (i.e., single arg) but  
eliminate the decisions regarding the optional arg from the recursive  
calls:
(defun kill-nil (l)
   (labels ((kill-nil-aux (l result)
  (cond ((endp l) (nreverse result))
((null (first l)) (kill-nil-aux (rest l) result))
(t (kill-nil-aux (rest l) (cons (first l)  
result ))
 (kill-nil-aux l '(

In the Clojure version above there doesn't seem to be any penalty  
since the recur only occurs after the correct arity has been selected.

Is this correct? How about a more traditional recursion?
(defn kill-nil
   ([l] (kill-nil l '()))
   ([l result] (cond (nil? l) (reverse result)
 (nil? (first l)) (recur (rest l) result)
 true (kill-nil (rest l) (cons (first l)  
result )

Is there a penalty deciding which arity to use on each call?

Aloha,
David Sletten

--~--~-~--~~~---~--~~
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
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: Flatten a list

2009-02-24 Thread Sean



On Feb 24, 11:35 pm, David Sletten da...@bosatsu.net wrote:
 On Feb 24, 2009, at 6:07 PM, David Sletten wrote:



  (defn kill-nil
     ([l] (kill-nil l '()))
     ([l result] (cond (nil? l) (reverse result)
                       (nil? (first l)) (recur (rest l) result)
                       true (recur (rest l) (cons (first l) result )

 I forgot to ask...

 In Lisp, rather than repeatedly testing for an optional argument like  
 this:
 (defun kill-nil (l optional (result '()))
    (cond ((endp l) (nreverse result))
          ((null (first l)) (kill-nil (rest l) result))
          (t (kill-nil (rest l) (cons (first l) result )

 I would preserve the interface to the user (i.e., single arg) but  
 eliminate the decisions regarding the optional arg from the recursive  
 calls:
 (defun kill-nil (l)
    (labels ((kill-nil-aux (l result)
               (cond ((endp l) (nreverse result))
                     ((null (first l)) (kill-nil-aux (rest l) result))
                     (t (kill-nil-aux (rest l) (cons (first l)  
 result ))
      (kill-nil-aux l '(

 In the Clojure version above there doesn't seem to be any penalty  
 since the recur only occurs after the correct arity has been selected.

 Is this correct? How about a more traditional recursion?
 (defn kill-nil
    ([l] (kill-nil l '()))
    ([l result] (cond (nil? l) (reverse result)
                      (nil? (first l)) (recur (rest l) result)
                      true (kill-nil (rest l) (cons (first l)  
 result )

 Is there a penalty deciding which arity to use on each call?

It depends if I'm on your lawn.


 Aloha,
 David Sletten
--~--~-~--~~~---~--~~
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
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
-~--~~~~--~~--~--~---



More Concise flatten, separate

2008-10-17 Thread Mark McGranaghan

Now that we have remove (and sequential?), perhaps we should
redefine flatten and separate:

(defn flatten
  Takes any nested combination of sequential things (lists, vectors,
  etc.) and returns their contents as a single, flat sequence.
  [x]
  (remove sequential? (tree-seq sequential? seq x)))

(defn separate
  Returns a vector:
   [ (filter f s), (remove f s) ]
  [f s]
  [(filter f s) (remove f s)])

- Mark
--~--~-~--~~~---~--~~
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
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---