Why do is used in this function?

1 view
Skip to first unread message

HB

unread,
Aug 31, 2010, 10:33:32 AM8/31/10
to Clojure
Hey,
Having this function:

(defn printall [s]
(if (not (empty? s))
(do
(println (str "Item: " (first s)))
(recur (rest s)))))

Why do is used here? what happens if I drop it?
Thanks for help and time.

Baishampayan Ghose

unread,
Aug 31, 2010, 10:39:18 AM8/31/10
to clo...@googlegroups.com

In Clojure and most other Lisps, `if' has the following structure -

(if test
then
else)

If you want to have multiple forms in the `then' or `else' clause, you
have to group them together, else it will become a part of the `then'
clause (or will throw an error since if can take only three args).
This also tells you that you are performing a side-effect since (do
foo bar) will return the return value of bar and that of foo will be
completely discarded.

Coming back to your example, if you drop the do, then only the println
part will be the `then' clause and the recur part will become the
'else' clause and will get executed only when the test is false.

This will make the function print the first item and exit.

I hope that was clear enough.

Regards,
BG

--
Baishampayan Ghose
b.ghose at gmail.com

Nicolas Oury

unread,
Aug 31, 2010, 10:57:06 AM8/31/10
to clo...@googlegroups.com
One solution to remove it is to use when.

(when (not (empty? s)


(println (str "Item: " (first s)))
(recur (rest s))))

As there is only one case for a when, you can give multiple
instructions for this case without grouping them
Even better:

(when-not (empty? s)

Justin Kramer

unread,
Aug 31, 2010, 11:08:29 AM8/31/10
to Clojure
Another tip: per the doc for 'empty?', (seq s) is preferred over (not
(empty? s)). Oh, and 'str' isn't necessary since 'println' adds spaces
between arguments:

(defn printall [s]
(when (seq s)
(println "Item:" (first s))
(recur (rest s))))

Justin

Chouser

unread,
Aug 31, 2010, 1:16:07 PM8/31/10
to clo...@googlegroups.com
On Tue, Aug 31, 2010 at 11:08 AM, Justin Kramer <jkkr...@gmail.com> wrote:
> Another tip: per the doc for 'empty?', (seq s) is preferred over (not
> (empty? s)). Oh, and 'str' isn't necessary since 'println' adds spaces
> between arguments:
>
> (defn printall [s]
>  (when (seq s)
>   (println "Item:" (first s))
>   (recur (rest s))))

Good tips! Another option:

(defn printall [s]
(doseq [i s]
(println "Item:" i)))

--Chouser
http://joyofclojure.com/

Reply all
Reply to author
Forward
0 new messages