Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does one know when to newline in Clojure/Lisp in general?

Here is a bit of example code:

(deftype Deck52 [suits] :as this
  DeckOfCards
  (check-empty []
               (Deck52. (apply hash-map 
                              (apply concat (remove (-> nil?) 
                                                    (for [[key val] suits] 
                                                      (if (empty? val) nil [key val])))))))
  (remove-card [suit card]
               (assoc suits suit (remove #(= card %) (suit suits))))

  (get-card [suit]
            (let [suitd (suit suits)]
              [(first suitd) (check-empty (Deck52. (assoc suits suit (rest suitd))))]))

  (random-card []
               (let [suitn (+ 1 (rand-int 4))]
                 (cond (= suitn 1) (get-card this :hearts)
                       (= suitn 2) (get-card this :diamonds)
                       (= suitn 3) (get-card this :clubs)
                       (= suitn 4) (get-card this :spades)))))

I also posted this code in a Gist here if it's easier to read: http://gist.github.com/307425 (not going anywhere).

The primary example here is check-empty. I had great difficulty knowing where I should and shouldn't hit return, and I still don't know if I did it right. It threatens to walk right off the right side of the screen, but that's the way clojure-mode indents, and I assume that it's supposed to be like that.

So, the question is, when is it time to place a newline in Clojure/Lisp code? Am I 'doin' it rite'?

NOTE: I can't promise that the code I posted works. I've been doing some experimentation, and some things might be plain ol' sucky, if not broken.

like image 571
Rayne Avatar asked Feb 18 '10 07:02

Rayne


1 Answers

The way you broke the lines is quite normal. I would do some slight changes though.

  • Put the argument vectors on the next line.
  • Use different forms: the little -> and ->> helpers, condp, when, ...
  • If necessary, break the line immediately after the function name.

Here how I would go about this. (Disclaimer: My style. Yours might be different. YMMV!)

(deftype Deck52 [suits] :as this
  DeckOfCards
  (check-empty
    []
    (->> (for [[key val] suits]
           (when-not (empty? val)
             [key val]))
      (remove nil?)
      (apply concat)
      (apply hash-map)
      Deck52.))
  (remove-card
    [suit card]
    (assoc suits suit (remove #(= card %) (suit suits))))
  (get-card
    [suit]
    (let [suitd (suit suits)]
      [(first suitd)
       (->> (rest suitd)
         (assoc suits suit)
         Deck52.
         check-empty)]))
  (random-card
    []
    (let [suitn (+ 1 (rand-int 4))]
      (condp = suitn
        1 (get-card this :hearts)
        2 (get-card this :diamonds)
        3 (get-card this :clubs)
        4 (get-card this :spades)))))

Although the following is not part of your question, I cannot resist:

(deftype Deck52 [suits] :as this
  DeckOfCards
  (check-empty
    []
    (->> suits (remove (comp nil? seq val)) (into {}) Deck52.))
  (remove-card
    [suit card]
    (update-in suits [suit] #(remove %2 %1) #(= card %)))
  (get-card
    [suit]
    (let [suitd (get suits suit)]
      [(first suitd)
       (->> (rest suitd) (assoc suits suit) Deck52. check-empty)]))
  (random-card
    []
    (case (rand-int 4)
      0 (get-card this :hearts)
      1 (get-card this :diamonds)
      2 (get-card this :clubs)
      3 (get-card this :spades))))
like image 129
kotarak Avatar answered Sep 22 '22 11:09

kotarak