Arc Forumnew | comments | leaders | submitlogin
1 point by nlavine 6066 days ago | link | parent

That works, but it only eliminates half as much nesting. Would it work for more with first-class macros? (I'm just going to expand it into a compose call because I don't want to make it all one symbol)

  (defop circles req
    (compose
      svpage [svg (svg width 500 height 500) _]
      [repeat 20 _] svg
      (circle cs (read-range 100 400)
              cy (read-range 100 400)
              r (read-range 10 70)
              fill (rand-hex-color)
              opacity (num:/ (rand-range 4 8) 10))))


2 points by almkglor 6066 days ago | link

That won't work. You see, foo:bar in function position is handled specially:

  (idfn foo:bar)
  => (idfn (compose foo bar))

  (foo:bar idfn)
  => (foo (bar idfn))
Compose does not work with macros.

But really, what improvement in readability do you get with the 'block style? The details of 'repeat etc. aren't very special-looking anymore.

-----

3 points by eds 6066 days ago | link

> Compose does not work with macros.

Exactly what do mean? Macros seem to work in functional position at least.

  arc> (and:or nil t)
  t
> But really, what improvement in readability do you get with the 'block style?

I agree with you on this. 'block doesn't really remove parens, it just moves them around and removes the nested structure. According to pg's Ansi Common Lisp, "Lisp programmers read and write code by indentation, not by parentheses." I find nested code to be more readable than flat code for exactly that reason, even if the parens stack up at the end of the block.

-----

1 point by almkglor 6066 days ago | link

This is because the expression:

  (and:or nil t)
expands to:

  (and (or nil t))
But the expression:

  (idfn and:or)
Expands to:

  (idfn (compose and or))
If you read my comment well, you'll see that I specifically mentioned that:

> You see, foo:bar in function position is handled specially:

-----

2 points by absz 6065 days ago | link

Actually, I believe what's happening is that

  (and:or nil t)
becomes

  ((compose and or) nil t)
, which is then expanded to

  (and (or nil t))
by ac.scm. Observe:

  arc> ((compose and or) nil t)
  t

-----

1 point by absz 6066 days ago | link

As almkglor observed, compose is handled specially in functional position, being expanded during compilation. Observe:

  arc> (and:or '(nil t))
  (nil t)
  arc> (apply and:or '(nil t))
  Error: "Function call on inappropriate object #3(tagged mac #<procedure>) (nil t)"

-----

2 points by eds 6066 days ago | link

Which is exactly what I meant by "macros seem to work in functional position." But amkglor's original statement "compose does not work with macros" does not take into account the special treatment of 'compose in functional position, which is why I was confused.

And if I am not mistaken, first class macros, once implemented, could be used in other situations like your example above.

-----

3 points by absz 6066 days ago | link

Looking at alkmglor's comment, it appears to indicate that a literal compose doesn't work; when it's optimized out, it works fine. In other words, everyone is vehemently agreeing with each other ;)

And of course, first class macros could do this. But we don't have those yet…

-----

1 point by nlavine 6065 days ago | link

I find it more readable personally, and definitely easier to write, if there are fewer parentheses at the end of the block. Also, the lack of indentation keeps things lined up nicely, without spilling them off the right edge of the screen.

But really, the block macro defines context (in fact, I considered calling it "context"). That is the semantic meaning. It gives you a list of expressions that define the context for the rest of the list.

I personally find it easier to read, but I am curious about whether other people do, and why or why not. You said the details of 'repeat don't look special anymore. Do you think they should?

-----