Skip to content

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Alternate Clojure syntax (work in progress...and NOT an April Fool's joke)
The majority of parens in Clojure are redundant if we just say that all
n > 1 tokens in a line are arguments to the first token. Parens can be
added in a more C-style to disambiguate within a line. Newline plus
indent expands argument list over multiple lines and each of those
lines gets the original "one-line" treatment. Introducing an "ignore
indent" sigil allows sugaring up the structure. The majority of calls
can be expressed in one line with no parens at all.
Hello world:
defn hello fn([] "Hello world")
hello
Partially expanded:
defn hello
fn [] "Hello world"
hello
Completely expanded (1ish node per line:
defn
hello
fn
[]
"Hello world"
hello
Immutable data structure example (mostly deleting parens):
let [my-vector [1 2 3 4]
my-map {:fred "ethel"}
my-list list(4 3 2 1)]
list
conj my-vector 5
assoc my-map :ricky "lucy"
conj my-list 5
;the originals are intact
my-vector
my-map
my-list
Completely expanded (showing indent and expansion of arrays)
let
[
my-vector
[
1
2
3
4
my-map
{
:fred
"ethel"
my-list
list
4
3
2
1
list
conj
my-vector
5
assoc
my-map
:ricky
"lucy"
conj
my-list
5
;the originals are intact
my-vector
my-map
my-list
Part of a bowling game kata:
0. original code
(defn score-game [rolls]
(loop [[frame left-rolls] (next-frame (parse-game rolls))
score 0]
(cond
(not (seq frame)) score
(spare? frame) (recur (next-frame left-rolls)
(+ score 10 (first left-rolls)))
(strike? frame) (recur (next-frame left-rolls)
(+ score 10 (first left-rolls) (second left-rolls)))
:else (recur (next-frame left-rolls)
(apply + score frame)))))
1. medium version using indent
defn score-game [rolls]
loop [[frame left rolls] next-frame(parse-game(rolls)) score 0]
cond
not seq(frame)
score
spare? frame
recur next-frame(left-rolls) +(score 10 first(left-rolls))
strike? frame
recur next-frame(left-rolls) +(score 10 first(left-rolls) second(left-rolls))
:else
recur next-frame(left-rolls) apply(+ score frame)
2. long, fewer parens
defn score-game [rolls]
loop
[[frame left rolls] next-frame(parse-game(rolls)) score 0]
cond
not seq(frame)
score
spare? frame
recur
next-frame left-rolls
+ score 10 first(left-rolls)
strike? frame
recur
next-frame left-rolls
+ score 10 first(left-rolls) second(left-rolls)
:else
recur
next-frame left-rolls
apply + score frame
3. short, more parens
defn score-game [rolls]
loop [[frame left rolls] next-frame(parse-game(rolls)) score 0]
cond
not(seq(frame)) score
spare?(frame) recur(next-frame(left-rolls) +(score 10 first(left-rolls)))
strike?(frame) recur(next-frame(left-rolls) +(score 10 first(left-rolls) second(left-rolls)))
:else recur(next-frame(left-rolls) apply(+ score frame))
4. one long line, most parens
defn score-game [rolls] loop([[frame left rolls] next-frame(parse-game(rolls)) score 0] cond(not(seq(frame)) score spare?(frame) recur(next-frame(left-rolls) +(score 10 first(left-rolls))) strike?(frame) recur(next-frame(left-rolls) +(score 10 first(left-rolls) second(left-rolls))) :else recur(next-frame(left-rolls) apply(+ score frame))))
5. medium, closer to original; => means "ignore indent", pure sugar
defn score-game [rolls]
loop [[frame left rolls] next-frame(parse-game(rolls)) score 0]
cond
not(seq(frame))
=> score
spare?(frame)
=> recur next-frame(left-rolls) +(score 10 first(left-rolls))
strike?(frame)
=> recur next-frame(left-rolls) +(score 10 first(left-rolls) second(left-rolls))
:else
=> recur next-frame(left-rolls) apply(+ score frame)
6. super long, 1ish node per line, minimum parens
defn
score-game
[
rolls
loop
[
[
frame
left
rolls
next-frame
parse-game
rolls
score
0
cond
not
seq
frame
score
spare?
frame
recur
next-frame
left-rolls
+
score
10
first
left-rolls
strike?
frame
recur
next-frame
left-rolls
+
score
10
first
left-rolls
second
left-rolls
:else
recur
next-frame
left-rolls
apply
+
score
frame
A simple macro. Nothing about this syntax loses homoiconity. It
it simply a different way to delimit sexps.
defmacro on-debug [& body]
`when DEBUG
do ~@body
@tomjack

On line 101 for example, why doesn't the sugar expand to a call to score with zero arguments?

@headius
Owner

@technomancy Consider it a thought exercise. All I'm doing here is delimiting sexps a different way; they're still there, line by line.

@tomjack score is defined in the loop preamble. It got lost in my initial translation, but I've fixed that now. You may have found an ambiguity, though, between a simple value and applying a zero-arg function; latter might need () to apply.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.