librelist archives

« back to archive

"Nil pun with care"

"Nil pun with care"

From:
Ali Baitam
Date:
2013-05-11 @ 04:58
Can someone explain this section in fewer words. I don't get it really. I
still don't understand when  when you should call (seq) and when you don't
need to.

Thanks

Re: [foray] "Nil pun with care"

From:
Solomon White
Date:
2013-05-11 @ 17:32
In some other lisps, you can write a recursive function to sum a list of
numbers like this:

```common-lisp
(defun summarize (list)
  (if list
    (+ (car list) (summarize (cdr list)))
    0)))

(summarize '(1 2 3))
# => 6
```

However, in clojure, the empty list is "truthy", so here's what happens:

```clojure
(defn summarize [list]
         (if list
           (+ (first list) (summarize (rest list)))
           0))

(summarize '(1 2 3))
StackOverflowError   clojure.lang.PersistentList$EmptyList.first
(PersistentList.java:148)
```

because it keeps trying to recurse into the empty list.  One way to fix it
is to use `seq` to make sure you don't get an empty list:

```clojure
(defn summarize [list]
  (let [s (seq list)]
    (if s
      (+ (first s) (summarize (rest s)))
      0)))

(summarize '(1 2 3))
# => 6
```


On Fri, May 10, 2013 at 10:58 PM, Ali Baitam <abaitam@gmail.com> wrote:

> Can someone explain this section in fewer words. I don't get it really. I
> still don't understand when  when you should call (seq) and when you don't
> need to.
>
> Thanks
>

Re: [foray] "Nil pun with care"

From:
Ali Baitam
Date:
2013-05-11 @ 19:32
That was straightforward. Thanks Solomon for taking the time to write this.


On Sat, May 11, 2013 at 1:32 PM, Solomon White <rubysolo@gmail.com> wrote:

> In some other lisps, you can write a recursive function to sum a list of
> numbers like this:
>
> ```common-lisp
> (defun summarize (list)
>   (if list
>     (+ (car list) (summarize (cdr list)))
>     0)))
>
> (summarize '(1 2 3))
> # => 6
> ```
>
> However, in clojure, the empty list is "truthy", so here's what happens:
>
> ```clojure
> (defn summarize [list]
>          (if list
>            (+ (first list) (summarize (rest list)))
>            0))
>
> (summarize '(1 2 3))
> StackOverflowError   clojure.lang.PersistentList$EmptyList.first
> (PersistentList.java:148)
> ```
>
> because it keeps trying to recurse into the empty list.  One way to fix it
> is to use `seq` to make sure you don't get an empty list:
>
> ```clojure
> (defn summarize [list]
>   (let [s (seq list)]
>     (if s
>       (+ (first s) (summarize (rest s)))
>       0)))
>
> (summarize '(1 2 3))
> # => 6
> ```
>
>
> On Fri, May 10, 2013 at 10:58 PM, Ali Baitam <abaitam@gmail.com> wrote:
>
>> Can someone explain this section in fewer words. I don't get it really. I
>> still don't understand when  when you should call (seq) and when you don't
>> need to.
>>
>> Thanks
>>
>
>

Re: [foray] "Nil pun with care"

From:
i-blis
Date:
2013-05-12 @ 12:34
<div>It seems to be idiomatic to use the if-let macro here in order to 
avoid nesting: </div><div> </div><div>```</div><div><div>(defn summarize 
[list]</div><div>  (if-let [s (seq list)]</div><div>    (+ (first s) 
(summarize (rest s)))</div><div>    
0))</div></div><div>``` </div><div> </div><div>The full reduce would look 
like this (I presume):</div><div> </div><div>```</div><div><div>(defn 
summarize-with </div><div>  ([f coll]</div><div>    (if-let [s (seq 
coll)]</div><div>      (summarize-with f (first s) (next s))</div><div>   
  (f)))</div><div>  ([f val coll]</div><div>    (if-let [s (seq 
coll)]</div><div>      (summarize-with f (f val (first s)) (next 
s))</div><div>      val)))</div><div> </div><div><div>(summarize-with + [1
2 3])       ;; => 6</div><div>(summarize-with str [\a \b \c])  ;; =>
"abc"</div></div></div><div>```</div><div> </div><div>Something I came 
across recently is the fact that many two arguments functions return their
neutral element, which is pretty useful in a 
reduce:</div><div>```</div><div>(*)     ;; => 1</div><div>(+)    ;; 
=> 0</div><div>(str)  ;; => ""</div><div>(list)  ;; => 
()</div><div>```</div><div>Greetings from East Berlin, 
i-blis.</div><div> </div><div>11.05.2013, 23:33, "Ali Baitam" 
<abaitam@gmail.com>:</div><blockquote type="cite"><div 
dir="ltr">That was straightforward. Thanks Solomon for taking the time to 
write this.</div><div><br /><br /><div>On Sat, May 11, 2013 at 1:32 PM, 
Solomon White <span dir="ltr"><<a href="mailto:rubysolo@gmail.com" 
target="_blank">rubysolo@gmail.com</a>></span> wrote:<br /><blockquote 
style="margin:0 0 0 0.8ex;border-left:1px #ccc 
solid;padding-left:1ex;"><div dir="ltr">In some other lisps, you can write
a recursive function to sum a list of numbers like 
this:<div> </div><div>```common-lisp</div><div>(defun summarize 
(list)</div><div>  (if list</div><div>    (+ (car list) (summarize (cdr 
list)))</div><div>    0)))</div><div> </div><div><div>(summarize '(1 2 
3))</div><div># => 6</div></div><div>```</div><div> </div><div>However,
in clojure, the empty list is "truthy", so here's what 
happens:</div><div> </div><div>```clojure</div><div><div>(defn summarize 
[list]</div><div>         (if list</div><div>           (+ (first list) 
(summarize (rest list)))</div><div>          
 0))</div><div> </div><div>(summarize '(1 2 
3))</div><div>StackOverflowError   
clojure.lang.PersistentList$EmptyList.first 
(PersistentList.java:148)</div><div>```</div><div> </div><div>because it 
keeps trying to recurse into the empty list.  One way to fix it is to use 
`seq` to make sure you don't get an empty 
list:</div><div> </div><div>```clojure</div><div><div>(defn summarize 
[list]</div><div>  (let [s (seq list)]</div><div>    (if s</div><div>     
(+ (first s) (summarize (rest s)))</div><div>      
0)))</div></div><div><div> </div><div>(summarize '(1 2 3))</div><div># 
=> 6</div><div>```</div></div></div></div><div><div><div><br /><br 
/><div>On Fri, May 10, 2013 at 10:58 PM, Ali Baitam <span dir="ltr"><<a
href="mailto:abaitam@gmail.com" 
target="_blank">abaitam@gmail.com</a>></span> wrote:<br /><blockquote 
style="margin:0 0 0 0.8ex;border-left:1px #ccc 
solid;padding-left:1ex;"><div dir="ltr">Can someone explain this section 
in fewer words. I don't get it really. I still don't understand when  when
you should call (seq) and when you don't need 
to.<div> </div><div>Thanks</div></div></blockquote></div></div></div></div></blockquote></div></div></blockquote>

Re: [foray] "Nil pun with care"

From:
i-blis
Date:
2013-05-12 @ 13:14
It seems to be idiomatic to use the if-let macro here in order to avoid nesting:

```
(defn summarize [list]
  (if-let [s (seq list)]
    (+ (first s) (summarize (rest s)))
    0))
```

The full reduce would look like this (I presume):

```
(defn summarize-with
  ([f coll]
    (if-let [s (seq coll)]
      (summarize-with f (first s) (next s))
      (f)))
  ([f val coll]
    (if-let [s (seq coll)]
      (summarize-with f (f val (first s)) (next s))
      val)))

(summarize-with + [1 2 3])       ;; => 6
(summarize-with str [\a \b \c])  ;; => "abc"
```

Something I came across recently is the fact that many two arguments 
functions return their neutral element, which is pretty useful in a 
reduce:
```
(*)     ;; => 1
(+)    ;; => 0
(str)  ;; => ""
(list)  ;; => ()
```
Greetings from East Berlin, i-blis.


11.05.2013, 23:33, "Ali Baitam" <abaitam@gmail.com>:
> That was straightforward. Thanks Solomon for taking the time to write this.
>
> On Sat, May 11, 2013 at 1:32 PM, Solomon White <rubysolo@gmail.com> wrote:
>> In some other lisps, you can write a recursive function to sum a list 
of numbers like this:
>> ```common-lisp
>> (defun summarize (list)
>>   (if list
>>     (+ (car list) (summarize (cdr list)))
>>     0)))
>>
>> (summarize '(1 2 3))
>> # => 6
>>
>> ```
>>
>> However, in clojure, the empty list is "truthy", so here's what happens:
>>
>> ```clojure
>> (defn summarize [list]
>>          (if list
>>            (+ (first list) (summarize (rest list)))
>>            0))
>>
>> (summarize '(1 2 3))
>> StackOverflowError   clojure.lang.PersistentList$EmptyList.first 
(PersistentList.java:148)
>> ```
>>
>> because it keeps trying to recurse into the empty list.  One way to fix
it is to use `seq` to make sure you don't get an empty list:
>>
>> ```clojure
>> (defn summarize [list]
>>   (let [s (seq list)]
>>     (if s
>>       (+ (first s) (summarize (rest s)))
>>       0)))
>>
>> (summarize '(1 2 3))
>> # => 6
>> ```
>>
>> On Fri, May 10, 2013 at 10:58 PM, Ali Baitam <abaitam@gmail.com> wrote:
>>> Can someone explain this section in fewer words. I don't get it 
really. I still don't understand when  when you should call (seq) and when
you don't need to.
>>> Thanks

Re: [foray] "Nil pun with care"

From:
Ali Baitam
Date:
2013-05-12 @ 19:05
Thanks i-blis. Solomon wrote the function summarize just to explain to me
when to use 'seq' and it did the job very well. Your idiomatic addition was
very useful as well as the last remark which I didn't know about either.
Thanks for that.

Greetings from Toronto, Ali.


On Sun, May 12, 2013 at 9:14 AM, i-blis <i-blis@yandex.ru> wrote:

> It seems to be idiomatic to use the if-let macro here in order to avoid
> nesting:
>
> ```
> (defn summarize [list]
>   (if-let [s (seq list)]
>     (+ (first s) (summarize (rest s)))
>     0))
> ```
>
> The full reduce would look like this (I presume):
>
> ```
> (defn summarize-with
>   ([f coll]
>     (if-let [s (seq coll)]
>       (summarize-with f (first s) (next s))
>       (f)))
>   ([f val coll]
>     (if-let [s (seq coll)]
>       (summarize-with f (f val (first s)) (next s))
>       val)))
>
> (summarize-with + [1 2 3])       ;; => 6
> (summarize-with str [\a \b \c])  ;; => "abc"
> ```
>
> Something I came across recently is the fact that many two arguments
> functions return their neutral element, which is pretty useful in a reduce:
> ```
> (*)     ;; => 1
> (+)    ;; => 0
> (str)  ;; => ""
> (list)  ;; => ()
> ```
> Greetings from East Berlin, i-blis.
>
>
> 11.05.2013, 23:33, "Ali Baitam" <abaitam@gmail.com>:
> > That was straightforward. Thanks Solomon for taking the time to write
> this.
> >
> > On Sat, May 11, 2013 at 1:32 PM, Solomon White <rubysolo@gmail.com>
> wrote:
> >> In some other lisps, you can write a recursive function to sum a list
> of numbers like this:
> >> ```common-lisp
> >> (defun summarize (list)
> >>   (if list
> >>     (+ (car list) (summarize (cdr list)))
> >>     0)))
> >>
> >> (summarize '(1 2 3))
> >> # => 6
> >>
> >> ```
> >>
> >> However, in clojure, the empty list is "truthy", so here's what happens:
> >>
> >> ```clojure
> >> (defn summarize [list]
> >>          (if list
> >>            (+ (first list) (summarize (rest list)))
> >>            0))
> >>
> >> (summarize '(1 2 3))
> >> StackOverflowError   clojure.lang.PersistentList$EmptyList.first
> (PersistentList.java:148)
> >> ```
> >>
> >> because it keeps trying to recurse into the empty list.  One way to fix
> it is to use `seq` to make sure you don't get an empty list:
> >>
> >> ```clojure
> >> (defn summarize [list]
> >>   (let [s (seq list)]
> >>     (if s
> >>       (+ (first s) (summarize (rest s)))
> >>       0)))
> >>
> >> (summarize '(1 2 3))
> >> # => 6
> >> ```
> >>
> >> On Fri, May 10, 2013 at 10:58 PM, Ali Baitam <abaitam@gmail.com> wrote:
> >>> Can someone explain this section in fewer words. I don't get it
> really. I still don't understand when  when you should call (seq) and when
> you don't need to.
> >>> Thanks
>
>