Arc Forumnew | comments | leaders | submitlogin
1 point by Adlai 5642 days ago | link | parent

I think there's a general tradition in Lisp indentation, which works essentially as follows:

Function calls are indented with all the arguments starting at the same column, for example:

  (calculate-fn-of arg1
                   arg2
                   arg3)
Macro calls are indented with the arguments two spaces in, for example:

  (while (< x 10)
    (prn x)
    (++ x))
This is usually done to emphasize the "body" of the macro arguments. So in macros which take several arguments before the "body" code, you'd put those arguments either on the same line, or indented in some way to distinguish them from the body. For example:

  (with (var1   val1
         thing2 val2
         var3   expr3)
    (do
      (stuff)
      (with-vars)))
However, some forms are indented differently for clarity. This doesn't seem to be as standardized. An example would be Arc's 'if macro. It makes sense to indent it with all the conditions on one line, but where do the result forms go? Possibilities are:

  (if (test1)
       (response1)
      (test2)
       (response2)
      (response3))

  (if (test1) (response1)
      (test2) (response2)
              (response3))

  (if (test1)
      (response1)
      (test2)
      (response2)
      (response3))

  (if
    (test1)
      (response1)
    (test2)
      (response2)
    (response3))
I actually haven't seen the last form used at all, but it seems very clear to me. I'm guessing some convention will emerge over time.


1 point by shader 5641 days ago | link

I just noticed that there is a file named CONVENTIONS in Anarki that states comment and indentation conventions for arc. They say pretty much what has been said so far, but may be worth looking at if you are interested.

-----

1 point by conanite 5642 days ago | link

I usually

  (if a b
      c d
        e)
if it fits, otherwise

  (if a
      b
      c
      d
      e)
The wavy-style if indentations make me seasick.

-----

1 point by Adlai 5641 days ago | link

I think that your first example is probably best in terms of compactness and clarity (associating each condition with its corresponding code). The completely straight indentation can be difficult to scan quickly if you have more than one condition. IMO, the only problem with your first example is when the conditions span more than one line or are very long.

-----

1 point by Adlai 5641 days ago | link

In terms of 'if, I was looking through some of pg's code just now, and noticed that he does use the wavy form of indentation. Thus, if you're big on proof by authority, the correct form of indentation for 'if would be the wavy one...

-----

3 points by conanite 5641 days ago | link

I was looking through some of pg's code just now

arc code or scheme code?

I once heard a great teacher say that appeal to authority is flawed rhetoric, so I never do it :)

-----

2 points by shader 5640 days ago | link

Never heard that one before ^^

However, in this case I agree with Adlai: pg had even planned on getting ppr to "properly indent long ifs". I presume that means to implement the wavy feature. It's also the convention for Anarki, according to the CONVENTIONS file.

So, here's what I'm thinking should be done for ifs:

1) If you only have three expressions, if-then-else, use:

  (if a
      b
      c)
1) If you like the format, and the expressions are very short use:

  (if a b
      c d
      ...
        e)
3) If you don't like that form, or the expressions are longer, use:

  (if (a       )
        (b       )
      (c       )
        (d       )
      (e       ))
I'm not sure whether to use one or two spaces between clauses. The anarki conventions file uses two spaces. Elsewhere I've seen only one space. So, which is it? Now or never ;)

(I'm writing a new version of ppr with proper indentation of forms, in case you wanted to know why I'm so interested in the indentation question)

-----

2 points by Adlai 5640 days ago | link

I think two is better, because it a) clearly distinguishes it as indentation (rather than just an accidental #\space), and b) it's consistent with the indentation of macros & co.

-----

1 point by shader 5638 days ago | link

Two spaces it is.

Another question:

How do people indent do, and, or, etc.:

a)

  (do abc
      bcd
      cde)
or b)

  (do
    abc
    bcd
    cde)
Choice a is more like a function call, b is more like a macro. Should it be a community standard, or on a user by user basis?

-----

1 point by CatDancer 5638 days ago | link

I use A, for me the space taken up by the extra indentation is less than the extra line taken up for B.

I don't use indentation as a way to indicate whether I'm calling a function or using a macro.

-----

1 point by shader 5638 days ago | link

Next question:

Should case be indented like 'if:

  (case
    a
      (b     )
    c
      (d     )
    (e      ))
or in pairs like with:

  (case
     a (b    )
     c (d    )
     (e     ))
?

Should it depend on whether they fit on one line or not? If they don't fit, should it still be like b., just with the second part spilling onto the next line?

-----

1 point by CatDancer 5638 days ago | link

I use the second if it fits OK, or the first if they don't fit.

-----

1 point by absz 5637 days ago | link

Ditto, except I write

  (case
    a-short     (b ...)
    c-very-long (d ...)
                (e ...))
when everything is on one line, and

  (case
    a-short
      (b ...)
    c-very-long
      (d ...)
    ; else
      (e ...))
when it doesn't (though I go back and forth about the ; else).

-----

1 point by shader 5636 days ago | link

Your first version is the one currently implemented by ppr.arc. If you would like, you can write the indentation function for your second version (it can even include the "; else")

Otherwise I think that the first version is generally clearer, and the second is rarely needed, as the value of the case statement can't usually be very long. Could you give me an example where you use your second version?

-----

1 point by absz 5636 days ago | link

Sure; here's something from my tagged-unions.arc on Anarki (Arc 2). It's responsible for parsing the types specified for slots in the tagged union:

  (each type-frag types
    ; Assemble the ('type name) pairs into two lists, so that we can iterate
    ; through them.
    (case (type type-frag)
      ; If it's a symbol, then we're defining a new name; add a new set of
      ; values, and go.
      sym
        (do
          (zap [cons type-frag _] names)
          (zap [cons nil       _] values))
      ; Otherwise, we're adding a value to an existing variant.
      cons
        ; I changed my mind about the order (now it's (name pred?) instead of
        ; (pred? name)), so I'm reversing it here.
        (zap [cons (rev type-frag) _] (car values))
      ; else
        (err "Invalid member of tagged union declaration.")))
I should also add (just as another data point) that my multi-condition ifs look like that too, and single-condition ifs look like the following:

  (def macexn (n expr)
    " Macroexpand `expr' `n' times.  NB: `expr' *is* evaluated!
      See also [[macex1]] [[macex]] "
    (if (and (number n) (> n 0))
      (macexn (- n 1) (macex1 expr))
      expr))
I'm not hugely wedded to any of my conventions, though, and I haven't coded in Arc for quite a while anyway; this isn't intended to get you to change anything or convert people to my style. As I said, it's just another data point.

-----

1 point by Adlai 5641 days ago | link

Well, the 'if macro only exists (as a macro) in Arc.

However, the indentation actually isn't completely consistent. There are a bunch of places where pg does a straight indentation for 'if.

-----

1 point by pg 5641 days ago | link

I've never felt 100% sure about it though.

-----

1 point by Adlai 5641 days ago | link

Well, I think it adds just enough clarity to be worth the "seasickness". I guess it's also related to the indentation from CL 'cond:

  (cond ((condition1)
         (result-code1))
        ((condition2)
         (result-code2))
        (default-code))

-----