cond formatting

91 views
Skip to first unread message

cageface

unread,
Jun 22, 2010, 4:27:44 PM6/22/10
to Clojure
Picky syntax question:

In common lisp cond requires more parenthesization than clojure:

(cond
((evenp a) a) ;if a is even return a
((> a 7) (/ a 2)) ;else if a is bigger than 7 return a/2
((< a 5) (- a 1)) ;else if a is smaller than 5 return a-1
(t 17))

vs clojure:

(cond
(even? a) a ;if a is even return a
(> a 7) (/ a 2) ;else if a is bigger than 7 return a/2
(< a 5) (- a 1) ;else if a is smaller than 5 return a-1
t 17)

Of course, fewer parentheses are usually better, but I'm finding cond
in the second form a little harder to read with more complex clauses:

(defn compare-row [a b]
;; compare null rows as > to advance
cursor
(cond
(and (nil? a) (nil? b)) [0,0]
(and (nil? a) (not= b nil)) [1, 0]
(and (not= a nil) (nil? b)) [-1, 0]
true (loop [col 0 a a b b]
(let [cmp (compare-fields (first a) (first b))]
(if (and (< col (count a)) (= cmp 0))
(recur (+ 1 col) (rest a) (rest b))
[cmp,col])))))

In this case it takes some visual parsing to see what the predicates
and results are and if you break them up onto individual lines you
have to count evens to figure out what the results are. The extra
level of indentation in the CL case makes it a lot easier. The only
easy solution I've considered for this is to add an extra blank line
between each clause, but this looks weird.

Any thoughts on this or other approaches?

Tim Daly

unread,
Jun 22, 2010, 4:38:27 PM6/22/10
to clo...@googlegroups.com
Actually, being a common-lisper I end up re-keying my clojure
cond expressions every time. Either I end up putting the extra
levels of parens or I forget to properly "even-count".

Emacs paren-bouncing makes it easy to syntax check a common
lisp cond but fails badly with clojure cond. Emacs doesn't
even need to know that it is parsing lisp since paren-bouncing
is enabled even in fundamental-mode buffers. However, there
has to be a special parser for clojure.

I guess it just depends on what you are used to but in this
case the syntactic change seems spurious to me.

Tim Daly

David Nolen

unread,
Jun 22, 2010, 4:41:40 PM6/22/10
to clo...@googlegroups.com
On Tue, Jun 22, 2010 at 4:27 PM, cageface <mile...@gmail.com> wrote:

Any thoughts on this or other approaches?

(defn compare-row [a b]
  ;; compare null rows as > to advance
  cursor
  (cond
   (and (nil? a) (nil? b))     [0,0]
   (and (nil? a) (not= b nil)) [1, 0]
   (and (not= a nil) (nil? b)) [-1, 0]
   true                        (loop [col 0 a a b b]
                                 (let [cmp (compare-fields (first a) (first b))]
                                   (if (and (< col (count a)) (= cmp 0))
                                     (recur (+ 1 col) (rest a) (rest b))
                                     [cmp,col]))))) 

I like lining things up.
 

Michael Gardner

unread,
Jun 22, 2010, 4:50:21 PM6/22/10
to clo...@googlegroups.com
On Jun 22, 2010, at 3:27 PM, cageface wrote:

> In this case it takes some visual parsing to see what the predicates
> and results are and if you break them up onto individual lines you
> have to count evens to figure out what the results are. The extra
> level of indentation in the CL case makes it a lot easier. The only
> easy solution I've considered for this is to add an extra blank line
> between each clause, but this looks weird.
>
> Any thoughts on this or other approaches?

Try this:

(defn compare-row [a b]
;; compare null rows as > to advance cursor
(cond
(and (nil? a) (nil? b))
[0,0]
(and (nil? a) (not= b nil))
[1, 0]
(and (not= a nil) (nil? b))
[-1, 0]
true
(loop [col 0 a a b b]
(let [cmp (compare-fields (first a) (first b))]
(if (and (< col (count a)) (= cmp 0))
(recur (+ 1 col) (rest a) (rest b))
[cmp,col])))))

I do this with multi-line lets and hash-map initializations too:

(let [
foo
(calculate-foo arg1)
bar
(calculate-bar arg2)
extra-long-name
(calculate-extra-long-name arg3)]
(do-stuff))

(hash-map
:foo
(calculate-foo arg1)
:bar
(calculate-bar arg2)
:extra-long-name
(calculate-extra-long-name arg3))

cageface

unread,
Jun 22, 2010, 4:51:56 PM6/22/10
to Clojure
This is fine when you just have simple clauses like this, but what if
the clauses are more complex, even containing subclauses?

A quick scan through clojure contrib suggest that people are inserting
blank lines between clauses when they get more complex. I guess this
is idiomatic for clojure?

cageface

unread,
Jun 22, 2010, 4:55:31 PM6/22/10
to Clojure
This looks nice but requires more hand-indenting, right? I really like
being able to select a block in emacs and hit indent-region and get
predictably tidy code. (The failure of emacs to do this 100% with
scala code is a pet peeve).

Michael Gardner

unread,
Jun 22, 2010, 5:01:10 PM6/22/10
to clo...@googlegroups.com
On Jun 22, 2010, at 3:55 PM, cageface wrote:

> This looks nice but requires more hand-indenting, right? I really like
> being able to select a block in emacs and hit indent-region and get
> predictably tidy code. (The failure of emacs to do this 100% with
> scala code is a pet peeve).

Can't help you there, as I never use auto-indenting (nor emacs).

David Powell

unread,
Jun 22, 2010, 5:20:59 PM6/22/10
to Clojure

> (cond
> (even? a) a ;if a is even return a
> (> a 7) (/ a 2) ;else if a is bigger than 7 return a/2
> (< a 5) (- a 1) ;else if a is smaller than 5 return a-1
> t 17)

I tend to write the condition and action on separate lines, and put a
blank comment in between each, like this:

(cond
(even? a) ;if a is even return a
a
;;
(> a 7) ;else if a is bigger than 7 return a/2
(/ a 2)
;;
(< a 5) ;else if a is smaller than 5 return a-1
(- a 1)
;;
:else
17)

just to keep emacs's indentation and cursor movement happy.

--
Dave

Stefan Kamphausen

unread,
Jun 22, 2010, 5:50:20 PM6/22/10
to Clojure
Hi,

On 22 Jun., 22:27, cageface <milese...@gmail.com> wrote:
> Picky syntax question:
>[...]

I don't consider this picky. Many of Clojures differences to older
lisps are well-grounded. To me the removal of extra parens in cond is
not. During my time with Clojure I experienced this as a little
nuisance. Little because I don't need cond too often, but if I do, it
becomes rather big.

The indentation Emacs chooses when hitting M-q on an opening paren (or
when indenting a region using some other magic) is law in my opinion.
So, other indentation suggestions are a no-go.

Extra lines, be they empty or comments, waste precious vertical
space.

So, if there is any way of getting old-style cond back in Clojure, I'd
inc.

Just my 2ct.

Kind regards,
Stefan

Laurent PETIT

unread,
Jun 22, 2010, 6:09:19 PM6/22/10
to clo...@googlegroups.com
2010/6/22 Stefan Kamphausen <ska...@googlemail.com>:

> The indentation Emacs chooses when hitting M-q on an opening paren (or
> when indenting a region using some other magic) is law in my opinion.

emacs bending your mind as nauseum :-)

cageface

unread,
Jun 22, 2010, 6:11:16 PM6/22/10
to Clojure
I think I'm going to take this route. The style seems pretty common in
clojure contrib and it's readable, if a bit odd at first.

rob levy

unread,
Jun 22, 2010, 7:42:37 PM6/22/10
to clo...@googlegroups.com
user=> (ns utils) 
utils=> (ns-unmap 'utils 'cond)
utils=> (defmacro cond [& body] `(clojure.core/cond ~@(apply concat body))) 
#'utils/cond
utils=> (macroexpand-1 '(cond (false "false") (true "true")))
(clojure.core/cond false "false" true "true")
utils=> (cond
              (false "false")
              (true "true"))
"true"


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

Howard Lewis Ship

unread,
Jun 22, 2010, 8:15:32 PM6/22/10
to clo...@googlegroups.com
On Tue, Jun 22, 2010 at 4:42 PM, rob levy <r.p....@gmail.com> wrote:
> user=> (ns utils)
> utils=> (ns-unmap 'utils 'cond)
> utils=> (defmacro cond [& body] `(clojure.core/cond ~@(apply concat body)))
> #'utils/cond
> utils=> (macroexpand-1 '(cond (false "false") (true "true")))
> (clojure.core/cond false "false" true "true")
> utils=> (cond
>               (false "false")
>               (true "true"))
> "true"
>

Yes, you CAN do that, but SHOULD you? If your code is maintained by
more than one person, and the version of cond used is inconsistent
from namespace to namespace, that's going to cause you a bit of grief
sooner or later!

--
Howard M. Lewis Ship

Creator of Apache Tapestry

The source for Tapestry training, mentoring and support. Contact me to
learn how I can get you up and productive in Tapestry fast!

(971) 678-5210
http://howardlewisship.com

Reply all
Reply to author
Forward
0 new messages