2015-01-03 04:56:07 +01:00
|
|
|
|
==============
|
|
|
|
|
Hy Style Guide
|
|
|
|
|
==============
|
|
|
|
|
|
|
|
|
|
“You know, Minister, I disagree with Dumbledore on many counts…but
|
|
|
|
|
you cannot deny he’s got style…”
|
2015-01-03 05:25:07 +01:00
|
|
|
|
— Phineas Nigellus Black, *Harry Potter and the Order of the Phoenix*
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
|
|
|
|
The Hy style guide intends to be a set of ground rules for the Hyve
|
|
|
|
|
(yes, the Hy community prides itself in appending Hy to everything)
|
|
|
|
|
to write idiomatic Hy code. Hy derives a lot from Clojure & Common
|
2015-12-08 14:43:47 +01:00
|
|
|
|
Lisp, while always maintaining Python interoperability.
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2015-01-03 04:58:46 +01:00
|
|
|
|
|
2015-01-03 04:56:07 +01:00
|
|
|
|
Prelude
|
2015-01-03 04:58:46 +01:00
|
|
|
|
=======
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
|
|
|
|
The Tao of Hy
|
2015-01-03 04:58:46 +01:00
|
|
|
|
-------------
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2015-01-03 05:25:07 +01:00
|
|
|
|
.. code-block:: none
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
|
|
|
|
Ummon asked the head monk, "What sutra are you lecturing on?"
|
|
|
|
|
"The Nirvana Sutra."
|
|
|
|
|
"The Nirvana Sutra has the Four Virtues, hasn't it?"
|
|
|
|
|
"It has."
|
|
|
|
|
Ummon asked, picking up a cup, "How many virtues has this?"
|
|
|
|
|
"None at all," said the monk.
|
|
|
|
|
"But ancient people said it had, didn't they?" said Ummon.
|
|
|
|
|
"What do you think of what they said?"
|
|
|
|
|
Ummon struck the cup and asked, "You understand?"
|
|
|
|
|
"No," said the monk.
|
|
|
|
|
"Then," said Ummon, "You'd better go on with your lectures on the sutra."
|
|
|
|
|
— the (koan) macro
|
|
|
|
|
|
|
|
|
|
The following illustrates a brief list of design decisions that went
|
|
|
|
|
into the making of Hy.
|
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
+ Look like a Lisp; DTRT with it (e.g. dashes turn to underscores).
|
2015-01-03 04:56:07 +01:00
|
|
|
|
+ We're still Python. Most of the internals translate 1:1 to Python internals.
|
2015-01-03 05:25:07 +01:00
|
|
|
|
+ Use Unicode everywhere.
|
|
|
|
|
+ Fix the bad decisions in Python 2 when we can (see ``true_division``).
|
2015-01-03 04:56:07 +01:00
|
|
|
|
+ When in doubt, defer to Python.
|
2015-01-03 05:25:07 +01:00
|
|
|
|
+ If you're still unsure, defer to Clojure.
|
|
|
|
|
+ If you're even more unsure, defer to Common Lisp.
|
2015-01-03 04:56:07 +01:00
|
|
|
|
+ Keep in mind we're not Clojure. We're not Common Lisp. We're
|
|
|
|
|
Homoiconic Python, with extra bits that make sense.
|
|
|
|
|
|
2015-01-03 04:58:46 +01:00
|
|
|
|
|
2015-01-03 04:56:07 +01:00
|
|
|
|
Layout & Indentation
|
2015-01-03 04:58:46 +01:00
|
|
|
|
====================
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
The #1 complaint about Lisp?
|
|
|
|
|
"It's too weird looking with all those parentheses! How do you even *read* that?"
|
|
|
|
|
And they're right! Lisp was originally much too hard to read.
|
|
|
|
|
Then they figured out indentation. And it was glorious.
|
|
|
|
|
|
|
|
|
|
The Three Laws
|
|
|
|
|
--------------
|
|
|
|
|
|
|
|
|
|
Here's the secret: *Real Lispers don't count the brackets.*
|
|
|
|
|
When reading Lisp, disregard the trailing brackets--those are for the computer, not the human.
|
|
|
|
|
As in Python, read the code structure by indentation.
|
|
|
|
|
These are the three laws that make this possible.
|
|
|
|
|
|
|
|
|
|
1. Brackets must *never* be left alone, sad and lonesome on their own line.
|
|
|
|
|
|
|
|
|
|
.. code-block:: clj
|
|
|
|
|
|
|
|
|
|
;; Good (and preferred)
|
|
|
|
|
(defn fib [n]
|
|
|
|
|
(if (<= n 2)
|
|
|
|
|
n
|
|
|
|
|
(+ (fib (- n 1))
|
|
|
|
|
(fib (- n 2)))))
|
|
|
|
|
|
|
|
|
|
;; Hysterically ridiculous
|
|
|
|
|
(defn fib [
|
|
|
|
|
n
|
|
|
|
|
] ; my eyes!
|
|
|
|
|
(if (<= n 2)
|
|
|
|
|
n
|
|
|
|
|
(+ (fib (- n 1)) (fib (- n 2)))
|
|
|
|
|
)
|
|
|
|
|
) ; GAH, BURN IT WITH FIRE
|
|
|
|
|
|
|
|
|
|
2. New lines must *always* be indented past their parent opening bracket.
|
|
|
|
|
|
|
|
|
|
.. code-block:: clj
|
|
|
|
|
|
|
|
|
|
;; Acceptable
|
|
|
|
|
(foo (, arg1
|
|
|
|
|
arg2))
|
|
|
|
|
|
|
|
|
|
;; Unacceptable
|
|
|
|
|
(foo (, arg1
|
|
|
|
|
arg2)) ; Doesn't go far enough.
|
|
|
|
|
|
|
|
|
|
;; Look at what happens if we remove the trailing brackets from the above examples.
|
|
|
|
|
;; Can you tell where they go?
|
|
|
|
|
|
|
|
|
|
(foo (, arg1
|
|
|
|
|
arg2
|
|
|
|
|
|
|
|
|
|
(foo (, arg1
|
|
|
|
|
arg2
|
|
|
|
|
|
|
|
|
|
;; Judging by indentation, this is where the brackets should go.
|
|
|
|
|
|
|
|
|
|
(foo (, arg1
|
|
|
|
|
arg2))
|
|
|
|
|
|
|
|
|
|
(foo (, arg1) ; not what we started with, is it?
|
|
|
|
|
arg2)
|
|
|
|
|
|
|
|
|
|
;; No, it's not at all obvious it should have gone the other way.
|
|
|
|
|
|
|
|
|
|
(fn [arg
|
|
|
|
|
arg
|
|
|
|
|
|
|
|
|
|
(fn [arg]
|
|
|
|
|
arg)
|
|
|
|
|
|
|
|
|
|
;; Beware of brackets with reader syntax. You still have to indent past them.
|
|
|
|
|
|
|
|
|
|
;; NO!
|
|
|
|
|
`#{(foo)
|
|
|
|
|
~@[(bar)
|
|
|
|
|
1 2]}
|
|
|
|
|
|
|
|
|
|
;; Good.
|
|
|
|
|
`#{(foo)
|
|
|
|
|
~@[(bar)
|
|
|
|
|
1
|
|
|
|
|
2]}
|
|
|
|
|
|
|
|
|
|
3. New lines must *never* be indented past the previous element's opening bracket.
|
|
|
|
|
|
|
|
|
|
.. code-block:: clj
|
|
|
|
|
|
|
|
|
|
;; BAD.
|
|
|
|
|
((get-fn q)
|
|
|
|
|
x
|
|
|
|
|
y)
|
|
|
|
|
|
|
|
|
|
;; The above with trailing brackets removed. See the problem?
|
|
|
|
|
((get-fn q
|
|
|
|
|
x
|
|
|
|
|
y
|
|
|
|
|
|
|
|
|
|
;; By indentation, this is where the brackets should go.
|
|
|
|
|
((get-fn q
|
|
|
|
|
x
|
|
|
|
|
y))
|
|
|
|
|
|
|
|
|
|
;; acceptable
|
|
|
|
|
((get-fn q) x ; the ")" on this line isn't trailing.
|
|
|
|
|
y)
|
|
|
|
|
|
|
|
|
|
;; preferred, since the ) should end the line.
|
|
|
|
|
((get-fn q)
|
|
|
|
|
x
|
|
|
|
|
y)
|
|
|
|
|
|
|
|
|
|
Furthermore
|
|
|
|
|
-----------
|
|
|
|
|
|
2015-01-03 04:56:07 +01:00
|
|
|
|
+ Avoid trailing spaces. They suck!
|
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
+ Limit lines to 100 characters.
|
|
|
|
|
|
|
|
|
|
+ Line up arguments to function calls when splitting over multiple lines.
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2015-01-03 06:05:02 +01:00
|
|
|
|
.. code-block:: clj
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
(foofunction arg1
|
|
|
|
|
(barfunction bararg1
|
|
|
|
|
bararg2
|
|
|
|
|
bararg3) ; aligned with bararg1
|
|
|
|
|
arg3)
|
|
|
|
|
|
|
|
|
|
(foofunction arg1
|
|
|
|
|
(barfunction bararg1
|
|
|
|
|
bararg2) ; Wrong. Looks like a macro body.
|
|
|
|
|
arg3)
|
|
|
|
|
|
|
|
|
|
(foofunction arg1
|
|
|
|
|
(barfunction bararg1 bararg2 bararg3) ; acceptable.
|
|
|
|
|
arg3)
|
|
|
|
|
|
|
|
|
|
;; indenting one space past the parent bracket is acceptable for long lines
|
|
|
|
|
(foofunction
|
|
|
|
|
arg1 ; acceptable, but better to keep it on the same line as foofunction
|
|
|
|
|
(barfunction
|
|
|
|
|
bararg1 ; indent again
|
|
|
|
|
bararg2
|
|
|
|
|
bararg3)
|
|
|
|
|
arg3) ; aligned with arg1
|
|
|
|
|
|
|
|
|
|
+ If you need to separate a bracket trail use a ``#_ /`` comment to hold it open.
|
|
|
|
|
(This avoids violating law #1.)
|
|
|
|
|
|
|
|
|
|
.. code-block:: clj
|
|
|
|
|
|
|
|
|
|
;; There are basically two reasons to do this--long lists under version control,
|
|
|
|
|
;; and when commenting out the final element during testing.
|
|
|
|
|
;; (Common Lisp might use #+(or) for this.)
|
|
|
|
|
|
|
|
|
|
;; preferred
|
|
|
|
|
[(foo)
|
|
|
|
|
(bar)
|
|
|
|
|
(baz)]
|
|
|
|
|
|
|
|
|
|
;; Acceptable if the list is long. (Three isn't that long though.)
|
|
|
|
|
;; This is better for version control line diffs.
|
|
|
|
|
[
|
|
|
|
|
(foo)
|
|
|
|
|
(bar)
|
|
|
|
|
(baz)
|
|
|
|
|
#_ /]
|
|
|
|
|
|
|
|
|
|
;; Unacceptable and an syntax error. Lost a bracket.
|
|
|
|
|
[(foo)
|
|
|
|
|
;; (bar)
|
|
|
|
|
;; (baz)]
|
|
|
|
|
|
|
|
|
|
;; Unacceptable. Broke law #1.
|
|
|
|
|
[(foo)
|
|
|
|
|
;; (bar)
|
|
|
|
|
;; (baz)
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
;; preferred
|
|
|
|
|
[(foo)
|
|
|
|
|
#_(bar)
|
|
|
|
|
#_(baz)]
|
|
|
|
|
|
|
|
|
|
;; acceptable
|
|
|
|
|
[(foo)
|
|
|
|
|
#_
|
|
|
|
|
(bar)
|
|
|
|
|
#_
|
|
|
|
|
(baz)]
|
|
|
|
|
|
|
|
|
|
;; acceptable
|
|
|
|
|
[(foo)
|
|
|
|
|
;; (bar)
|
|
|
|
|
;; (baz)
|
|
|
|
|
#_ /]
|
|
|
|
|
|
|
|
|
|
+ Brackets like to snuggle, don't leave them out in the cold!
|
|
|
|
|
|
|
|
|
|
.. code-block:: clj
|
|
|
|
|
|
|
|
|
|
;;; Good
|
|
|
|
|
[1 2 3]
|
|
|
|
|
(foo (bar 2))
|
|
|
|
|
|
|
|
|
|
;;; Bad
|
|
|
|
|
[ 1 2 3 ]
|
|
|
|
|
( foo ( bar 2 ) )
|
|
|
|
|
|
|
|
|
|
;;; Ugly
|
|
|
|
|
[ 1 2 3]
|
|
|
|
|
(foo( bar 2) )
|
|
|
|
|
|
|
|
|
|
+ Use whitespace to show implicit groups, but be consistent within a form.
|
|
|
|
|
|
|
|
|
|
.. code-block:: clj
|
|
|
|
|
|
|
|
|
|
;; Older Lisps would always wrap such groups in even more parentheses.
|
|
|
|
|
;; But Hy takes after Clojure, which has a lighter touch.
|
|
|
|
|
|
|
|
|
|
{1 9
|
|
|
|
|
2 8
|
|
|
|
|
3 7
|
|
|
|
|
4 6
|
|
|
|
|
5 5} ; newlines show key-value pairs in dict
|
|
|
|
|
|
|
|
|
|
;; This grouping makes no sense.
|
|
|
|
|
#{1 2
|
|
|
|
|
3 4} ; It's a set, so why are there pairs?
|
|
|
|
|
|
|
|
|
|
;; This grouping also makes no sense.
|
|
|
|
|
[1
|
|
|
|
|
1 2
|
|
|
|
|
1 2 3] ; wHy do you like random patterns? [sic pun, sorry]
|
|
|
|
|
|
|
|
|
|
;; BAD. Can't tell key from value without counting
|
|
|
|
|
{1 9 2 8 3 7 4 6 5 5}
|
|
|
|
|
|
|
|
|
|
;; Good. Extra spaces can work too, if it fits on one line.
|
|
|
|
|
{1 9 2 8 3 7 4 6 5 5}
|
|
|
|
|
|
|
|
|
|
;; Be consistent. Separate all groups the same way in a form.
|
|
|
|
|
|
|
|
|
|
{1 9 2 8
|
|
|
|
|
3 7 4 6 5 5} ; Pick one or the other!
|
|
|
|
|
{1 9 2 8 3 7 4 6 5 5} ; You forgot something.
|
|
|
|
|
|
|
|
|
|
;; Groups of one must also be consistent.
|
|
|
|
|
|
|
|
|
|
(foo 1 2 3} ; No need for extra spaces here.
|
|
|
|
|
(foo 1
|
|
|
|
|
2
|
|
|
|
|
3} ; Also acceptable, but you could have fit this on one line.
|
|
|
|
|
[1
|
|
|
|
|
2] ; same
|
|
|
|
|
(foo 1 2 ; This isn't a pair?
|
|
|
|
|
3) ; Lines or spaces--pick one or the other!
|
|
|
|
|
|
|
|
|
|
(foofunction (make-arg)
|
|
|
|
|
(get-arg)
|
|
|
|
|
#tag(do-stuff) ; Tags belong with what they tag.
|
|
|
|
|
#* args ; #* goes with what it unpacks.
|
|
|
|
|
#** kwargs)
|
|
|
|
|
|
|
|
|
|
;; Yep, those are pairs too.
|
|
|
|
|
(setv x 1
|
|
|
|
|
y 2)
|
|
|
|
|
|
|
|
|
|
+ Macros and special forms can have "special" arguments that are indented like function arguments.
|
|
|
|
|
|
|
|
|
|
+ Indent the non-special arguments (usually the body) one space past the parent bracket.
|
|
|
|
|
|
|
|
|
|
.. code-block:: clj
|
|
|
|
|
|
|
|
|
|
(assoc foo ; foo is special
|
|
|
|
|
"x" 1 ; remaining args are not special. Indent 2 spaces.
|
|
|
|
|
"y" 2)
|
|
|
|
|
|
|
|
|
|
;; The do form has no special args. Indent like a function call.
|
|
|
|
|
(do (foo)
|
|
|
|
|
(bar)
|
|
|
|
|
(baz))
|
|
|
|
|
|
|
|
|
|
;; No special args to distinguish, so this is also valid function indent.
|
|
|
|
|
(do
|
|
|
|
|
(foo)
|
|
|
|
|
(bar)
|
|
|
|
|
(baz))
|
|
|
|
|
|
|
|
|
|
;; Preferred.
|
2015-01-03 06:05:02 +01:00
|
|
|
|
(defn fib [n]
|
|
|
|
|
(if (<= n 2)
|
2015-09-22 19:39:08 +02:00
|
|
|
|
n
|
2018-06-11 07:03:05 +02:00
|
|
|
|
(+ (fib (- n 1)) ; else clause is not special, but aligning it is OK.
|
|
|
|
|
(fib (- n 2)))))
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
(defn fib
|
|
|
|
|
[n] ; name and argslist are special. Indent like function args.
|
|
|
|
|
;; defn body is not special. Indent 1 space past parent bracket.
|
2015-01-03 05:25:07 +01:00
|
|
|
|
(if (<= n 2)
|
2018-06-11 07:03:05 +02:00
|
|
|
|
n ; elif pairs are special, indent like function args
|
|
|
|
|
(+ (fib (- n 1)) ; else clause is not special. Indent 1 space past parent bracket.
|
|
|
|
|
(fib (- n 2)))))
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2015-01-03 06:05:02 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
+ Removing whitespace can also make groups clearer.
|
|
|
|
|
|
|
|
|
|
.. code-block:: clj
|
|
|
|
|
|
|
|
|
|
;;; lookups
|
|
|
|
|
;; acceptable
|
|
|
|
|
(. foo ["bar"])
|
|
|
|
|
;; preferred
|
|
|
|
|
(. foo["bar"])
|
|
|
|
|
|
|
|
|
|
;; Bad. Doesn't show groups clearly
|
|
|
|
|
(import foo foo [spam :as sp eggs :as eg] bar bar [bacon])
|
|
|
|
|
|
|
|
|
|
;; Acceptable. Extra spaces show groups.
|
|
|
|
|
(import foo foo [spam :as sp eggs :as eg] bar bar [bacon])
|
|
|
|
|
;; Preferred. Removing spaces is even clearer.
|
|
|
|
|
(import foo foo[spam :as sp eggs :as eg] bar bar[bacon])
|
|
|
|
|
|
|
|
|
|
;; Acceptable. Newlines show groups.
|
|
|
|
|
(import foo
|
|
|
|
|
foo [spam :as sp
|
|
|
|
|
eggs :as eg]
|
|
|
|
|
bar
|
|
|
|
|
bar [bacon])
|
|
|
|
|
;; Preferred, since it's more consistent with the preferred one-line version.
|
|
|
|
|
(import foo
|
|
|
|
|
foo[spam :as sp
|
|
|
|
|
eggs :as eg]
|
|
|
|
|
bar
|
|
|
|
|
bar[bacon])
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
;;; avoid whitespace after tags
|
|
|
|
|
|
|
|
|
|
;; Note which shows groups better.
|
|
|
|
|
|
|
|
|
|
(foofunction #tag "foo" #tag (foo) #* (get-args))
|
|
|
|
|
|
|
|
|
|
(foofunction #tag"foo" #tag(foo) #*(get-args))
|
|
|
|
|
|
|
|
|
|
;; Can't group these by removing whitespace, so use extra spaces instead.
|
|
|
|
|
(foofunction #x foo #x bar #* args)
|
|
|
|
|
|
|
|
|
|
;; Same idea.
|
|
|
|
|
(foofunction #x foo
|
|
|
|
|
#x bar
|
|
|
|
|
#* args)
|
|
|
|
|
|
|
|
|
|
;; Acceptable, but you don't need to separate function name from first arg.
|
|
|
|
|
(foofunction #x foo #x bar #* args)
|
|
|
|
|
|
|
|
|
|
;; Same idea. Keeping the first group on the same line as the function name is preferable.
|
|
|
|
|
(foofunction
|
|
|
|
|
#x foo
|
|
|
|
|
#x bar
|
|
|
|
|
#* args)
|
|
|
|
|
|
|
|
|
|
;; OK. It's still clear what this is tagging. And you don't have to re-indent.
|
|
|
|
|
#_
|
|
|
|
|
(def foo []
|
|
|
|
|
stuff)
|
|
|
|
|
|
|
|
|
|
;; also OK, but more work.
|
|
|
|
|
#_(def foo []
|
|
|
|
|
stuff)
|
|
|
|
|
|
|
|
|
|
;; Not OK, you messed up the indent and broke law #2.
|
|
|
|
|
#_(def foo []
|
|
|
|
|
stuff)
|
|
|
|
|
|
|
|
|
|
;; Not OK, keep the tag grouped with its argument.
|
|
|
|
|
#_
|
|
|
|
|
|
|
|
|
|
(def foo []
|
|
|
|
|
stuff)
|
|
|
|
|
|
|
|
|
|
+ Any closing bracket(s) (of any kind) must end the line,
|
|
|
|
|
unless it's in the middle of an implicit group that started on the line.
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2015-01-03 06:05:02 +01:00
|
|
|
|
.. code-block:: clj
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
;; One-liners are overrated.
|
|
|
|
|
;; Maybe OK if you're just typing into the REPL.
|
|
|
|
|
(defn fib [n] (if (<= n 2) n (+ (fib (- n 1)) (fib (- n 2))))) ; too hard to read!
|
|
|
|
|
|
|
|
|
|
;; getting better.
|
2015-01-03 06:05:02 +01:00
|
|
|
|
(defn fib [n]
|
|
|
|
|
(if (<= n 2)
|
2015-09-22 19:39:08 +02:00
|
|
|
|
n
|
2018-06-11 07:03:05 +02:00
|
|
|
|
(+ (fib (- n 1)) (fib (- n 2))))) ; still too hard on this line
|
|
|
|
|
|
|
|
|
|
;; How to do it.
|
|
|
|
|
(defn fib [n] ; Saw a "]", newline.
|
|
|
|
|
(if (<= n 2) n ; Saw a ")", but leave it since it's in a semantic pair starting in this line.
|
|
|
|
|
(+ (fib (- n 1)) ; Saw a "))" line break.
|
|
|
|
|
(fib (- n 2)))))
|
|
|
|
|
|
|
|
|
|
;; Acceptable. Pairs.
|
|
|
|
|
(print (if (< n 0.0) "negative"
|
|
|
|
|
(= n 0.0) "zero"
|
|
|
|
|
(> n 0.0) "positive"
|
|
|
|
|
:else "not a number")) ; :else is not magic; True would work also.
|
|
|
|
|
|
|
|
|
|
;; Bad. Doesn't separate groups.
|
|
|
|
|
(print (if (< n 0.0)
|
|
|
|
|
"negative"
|
|
|
|
|
(= n 0.0)
|
|
|
|
|
"zero"
|
|
|
|
|
(> n 0.0)
|
|
|
|
|
"positive"
|
|
|
|
|
"not a number"))
|
|
|
|
|
|
|
|
|
|
;; This is also acceptable.
|
|
|
|
|
(print (if (< n 0.0) "negative"
|
|
|
|
|
(= n 0.0) "zero"
|
|
|
|
|
(> n 0.0) (do (do-foo) ; Group started this line, so didn't break.
|
|
|
|
|
(do-bar)
|
|
|
|
|
"positive")
|
|
|
|
|
"not a number")) ; :else is implied for the last one.
|
|
|
|
|
|
|
|
|
|
;; Bad.
|
|
|
|
|
(print (if (< n 0.0) "negative"
|
|
|
|
|
(= n 0.0) "zero"
|
|
|
|
|
(and (even? n)
|
|
|
|
|
(> n 0.0)) "even-positive" ; Group not started this line! Should break on "))"
|
|
|
|
|
(> n 0.0) "positive"
|
|
|
|
|
"not a number"))
|
|
|
|
|
|
|
|
|
|
;; Worse.
|
|
|
|
|
(print (if (< n 0.0) "negative"
|
|
|
|
|
(= n 0.0) "zero"
|
|
|
|
|
(and (even? n)
|
|
|
|
|
(> n 0.0)) (do (do-foo) ; Group not started this line.
|
|
|
|
|
(do-bar)
|
|
|
|
|
"even-positive")
|
|
|
|
|
(> n 0.0) "positive"
|
|
|
|
|
"not a number"))
|
|
|
|
|
|
|
|
|
|
;; Good. Blank line separates groups.
|
|
|
|
|
(print (if (< n 0.0) "negative"
|
|
|
|
|
|
|
|
|
|
(= n 0.0) "zero"
|
|
|
|
|
|
|
|
|
|
(and (even? n)
|
|
|
|
|
(> n 0.0))
|
|
|
|
|
(do (do-foo)
|
|
|
|
|
(do-bar)
|
|
|
|
|
"even-positive")
|
|
|
|
|
|
|
|
|
|
(> n 0.0) "positive"
|
|
|
|
|
|
|
|
|
|
"not a number"))
|
|
|
|
|
|
|
|
|
|
;; Not so good, groups are not separated consistently.
|
|
|
|
|
(print (if (< n 0.0) "negative"
|
|
|
|
|
(= n 0.0) "zero"
|
|
|
|
|
|
|
|
|
|
(> n 0.0)
|
|
|
|
|
(do (do-foo)
|
|
|
|
|
"positive")
|
|
|
|
|
|
|
|
|
|
"not a number"))
|
|
|
|
|
|
|
|
|
|
;; Acceptable. All groups are separated the same way, with a blank like.
|
|
|
|
|
(print (if (< n 0.0) "negative"
|
|
|
|
|
|
|
|
|
|
(= n 0.0) "zero"
|
|
|
|
|
|
|
|
|
|
(> n 0.0)
|
|
|
|
|
(do (do-foo)
|
|
|
|
|
"positive")
|
|
|
|
|
|
|
|
|
|
"not a number"))
|
|
|
|
|
|
|
|
|
|
(defn fib [n] ; saw a "]", newline.
|
|
|
|
|
(if (<= n 2) ; OK to break here. Since there's only one pair, we don't have to separate them.
|
|
|
|
|
n
|
|
|
|
|
(+ (fib (- n 1)) ; non-special indent is another whitespace separation technique.
|
|
|
|
|
(fib (- n 2)))))
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
Comments
|
|
|
|
|
--------
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
Prefer docstrings to comments where applicable--in ``defn``, ``defclass``, and at the top of the module.
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
The ``(comment)`` macro is still subject to the three laws.
|
|
|
|
|
If you're tempted to violate them, consider discarding a string instead with ``#_``.
|
|
|
|
|
|
|
|
|
|
Semicolon comments shall start with some number of semicolons
|
|
|
|
|
and have a space between the semicolons and the start of the comment.
|
|
|
|
|
Also, try to not comment the obvious.
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
|
|
|
|
.. code-block:: clj
|
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
;;;; Major Header Labeling a Major Section
|
|
|
|
|
;; Headers should only be one line.
|
|
|
|
|
;; This is non-header commentary, but not about a particular form.
|
|
|
|
|
;; These can span multiple lines.
|
|
|
|
|
;; These are separated from the next form or form comment by a blank line.
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
;; Good.
|
|
|
|
|
(setv ind (dec x)) ; indexing starts from 0
|
|
|
|
|
; margin comment continues on the next line.
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
;; Style-compliant but just states the obvious.
|
|
|
|
|
(setv ind (dec x)) ; sets index to x-1
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
;; Bad.
|
|
|
|
|
(setv ind (dec x));typing words for fun
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
;;; Minor Header Comment Labeling a Minor Section
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
;; Comment about the whole foofunction call.
|
|
|
|
|
;; These can also span mulitple lines.
|
|
|
|
|
(foofunction ;; Form comment about (get-arg1). Not a margin comment!
|
|
|
|
|
(get-arg1)
|
|
|
|
|
;; Form comment about arg2. The indent matches.
|
|
|
|
|
arg2)
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
;;;; Footer
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Header comments shall not be indented, and shall appear only at the toplevel outside of any form.
|
|
|
|
|
They must always begin with at least three semicolons--usually ``;;;`` for minor and ``;;;;`` for major headings.
|
|
|
|
|
(Emacs recognizes these as headers.)
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
Form comments shall be indented at the same level as the form they're commenting about;
|
|
|
|
|
they must always start with exactly two semicolons ``;;``.
|
|
|
|
|
Form comments appear directly above what they're commenting on, never below.
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
General toplevel commentary shall not be indented;
|
|
|
|
|
they must always start with exactly two semicolons ``;;``
|
|
|
|
|
and be separated from the next form with a blank line.
|
|
|
|
|
For long commentary, consider using a ``#_`` applied to a string for this purpose instead.
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
Margin comments shall be two spaces from the end of the code; they
|
|
|
|
|
must always start with a single semicolon ``;``.
|
|
|
|
|
Margin comments may be continued on the next line.
|
|
|
|
|
|
|
|
|
|
When commenting out entire forms, prefer the ``#_`` syntax.
|
|
|
|
|
But if you do need line comments, use the more general double-colon form,
|
|
|
|
|
since they're not headers that should appear in the outline,
|
|
|
|
|
nor are they margin comment continuations that should be indented automatically.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Coding Style
|
|
|
|
|
============
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2015-01-03 05:25:07 +01:00
|
|
|
|
+ Use the threading macro or the threading tail macros when encountering
|
|
|
|
|
deeply nested s-expressions. However, be judicious when using them. Do
|
|
|
|
|
use them when clarity and readability improves; do not construct
|
|
|
|
|
convoluted, hard to understand expressions.
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2015-01-03 06:05:02 +01:00
|
|
|
|
.. code-block:: clj
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
;; Not so good.
|
|
|
|
|
(setv *names*
|
|
|
|
|
(with [f (open "names.txt")]
|
|
|
|
|
(sorted (.split (.replace (.strip (.read f))
|
|
|
|
|
"\""
|
|
|
|
|
"")
|
|
|
|
|
","))))
|
|
|
|
|
|
|
|
|
|
;; Preferred.
|
|
|
|
|
(setv *names*
|
|
|
|
|
(with [f (open "names.txt")]
|
|
|
|
|
(-> (.read f)
|
|
|
|
|
.strip
|
|
|
|
|
(.replace "\"" "")
|
|
|
|
|
(.split ",")
|
|
|
|
|
sorted)))
|
|
|
|
|
|
|
|
|
|
;; Probably not a good idea.
|
|
|
|
|
(setv square? [x]
|
|
|
|
|
(->> 2
|
|
|
|
|
(pow (int (sqrt x)))
|
|
|
|
|
(= x)))
|
|
|
|
|
|
|
|
|
|
;; better
|
|
|
|
|
(setv square? [x]
|
|
|
|
|
(-> x
|
|
|
|
|
sqrt
|
|
|
|
|
int
|
|
|
|
|
(pow 2)
|
|
|
|
|
(= x))
|
|
|
|
|
|
|
|
|
|
;; good
|
|
|
|
|
(setv square? [x]
|
|
|
|
|
(= x (-> x sqrt int (pow 2))))
|
|
|
|
|
|
|
|
|
|
;; still OK
|
|
|
|
|
(setv square? [x]
|
|
|
|
|
(= x (pow (int (sqrt x))
|
|
|
|
|
2))
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
|
|
|
|
|
2015-01-03 05:25:07 +01:00
|
|
|
|
+ Clojure-style dot notation is preferred over the direct call of
|
|
|
|
|
the object's method, though both will continue to be supported.
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2015-01-03 06:05:02 +01:00
|
|
|
|
.. code-block:: clj
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
;; Good.
|
2015-01-03 06:05:02 +01:00
|
|
|
|
(with [fd (open "/etc/passwd")]
|
2015-01-03 04:56:07 +01:00
|
|
|
|
(print (.readlines fd)))
|
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
;; Not so good.
|
2015-01-03 06:05:02 +01:00
|
|
|
|
(with [fd (open "/etc/passwd")]
|
2015-01-03 04:56:07 +01:00
|
|
|
|
(print (fd.readlines)))
|
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
+ Prefer hyphens when separating words. ``foo-bar``, not ``foo_bar``.
|
|
|
|
|
|
|
|
|
|
+ Don't use leading hyphens, except for "operators".
|
|
|
|
|
|
|
|
|
|
.. code-block:: clj
|
|
|
|
|
|
|
|
|
|
;; Clearly subtraction.
|
|
|
|
|
(-= spam 2)
|
|
|
|
|
(- 100 7)
|
|
|
|
|
|
|
|
|
|
;; What are you doing?
|
|
|
|
|
(_= spam 2)
|
|
|
|
|
(_ 100 7)
|
|
|
|
|
|
|
|
|
|
;; This looks weird.
|
|
|
|
|
(_>> foo bar baz)
|
|
|
|
|
|
|
|
|
|
;; OH, it's an arrow!
|
|
|
|
|
(->> foo bar baz)
|
|
|
|
|
|
|
|
|
|
;; Negative spam???
|
|
|
|
|
(setv -spam 100)
|
|
|
|
|
|
|
|
|
|
;; Oh, it's just a module private.
|
|
|
|
|
(setv _spam 100)
|
|
|
|
|
|
|
|
|
|
(class Foo []
|
|
|
|
|
;; Also weird.
|
|
|
|
|
(defn __init-- [self] ...))
|
|
|
|
|
|
|
|
|
|
(class Foo []
|
|
|
|
|
;; Less weird?
|
|
|
|
|
(defn --init-- [self] ...))
|
|
|
|
|
|
|
|
|
|
(class Foo []
|
|
|
|
|
;; Preferred!
|
|
|
|
|
(defn __init__ [self] ...))
|
|
|
|
|
|
|
|
|
|
;; This kind of name is OK, but would be module private. (No import *)
|
|
|
|
|
(def ->dict [&rest pairs]
|
|
|
|
|
(dict (partition pairs)))
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
|
|
|
|
Conclusion
|
2015-01-03 04:58:46 +01:00
|
|
|
|
==========
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2015-01-03 05:25:07 +01:00
|
|
|
|
“Fashions fade, style is eternal”
|
|
|
|
|
—Yves Saint Laurent
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
|
|
|
|
|
2015-01-03 05:25:07 +01:00
|
|
|
|
This guide is just a set of community guidelines, and obviously, community
|
|
|
|
|
guidelines do not make sense without an active community. Contributions are
|
|
|
|
|
welcome. Join us at #hy in freenode, blog about it, tweet about it, and most
|
|
|
|
|
importantly, have fun with Hy.
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Thanks
|
2015-01-03 04:58:46 +01:00
|
|
|
|
======
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2018-06-11 07:03:05 +02:00
|
|
|
|
+ This guide is heavily inspired from `@paultag`_ 's blog post `Hy Survival Guide`_
|
2015-01-03 04:56:07 +01:00
|
|
|
|
+ The `Clojure Style Guide`_
|
2018-06-11 07:03:05 +02:00
|
|
|
|
+ `Parinfer`_ and `Parlinter`_ (the three laws)
|
|
|
|
|
+ The Community Scheme Wiki `scheme-style`_ (ending bracket ends the line)
|
|
|
|
|
+ GNU Emacs Lisp Reference Manual `Comment-Tips`_ (how many semicolons?)
|
|
|
|
|
+ `Riastradh's Lisp Style Rules`_
|
2015-01-03 04:56:07 +01:00
|
|
|
|
|
2017-02-07 20:25:40 +01:00
|
|
|
|
.. _`Hy Survival Guide`: https://notes.pault.ag/hy-survival-guide/
|
2015-01-03 04:56:07 +01:00
|
|
|
|
.. _`Clojure Style Guide`: https://github.com/bbatsov/clojure-style-guide
|
|
|
|
|
.. _`@paultag`: https://github.com/paultag
|
2018-06-11 07:03:05 +02:00
|
|
|
|
.. _`Parinfer`: https://shaunlebron.github.io/parinfer/
|
|
|
|
|
.. _`Parlinter`: https://github.com/shaunlebron/parlinter
|
|
|
|
|
.. _`scheme-style`: http://community.schemewiki.org/?scheme-style
|
|
|
|
|
.. _`Comment-Tips`: https://www.gnu.org/software/emacs/manual/html_node/elisp/Comment-Tips.html
|
|
|
|
|
.. _`Riastradh's Lisp Style Rules`: http://mumble.net/~campbell/scheme/style.txt
|