何故 do ステートメントがグルーピングするのに必要なの?
まぁそうなるよね、という例。
(defn x [] (if true (do (println "a") (println "b")))) => (x) a b nil
do を使えば正常に動くけど、 do を抜かすと…
(defn x [] (if true ((println "a") (println "b")))) => (x) a b NullPointerException user/x (NO_SOURCE_FILE:3)
NPE になる。なんで?という話。
回答にあるように、
((println "a") (println "b"))
先の (println "a") が評価されると nil が返り…
(nil (println "b"))
となってしまうのでお馴染みのように、開き括弧の次にくる先頭の S 式は「関数」として扱われるので NPE となるわけですね。
なのでまぁこういうときは when という別のイディオムが用意されているのでそちらを使ったほうが楽だしいいよという話。