The reader parses the comma to make (unquote someobj!field) before ssyntax processing even occurs. I just wrote a long comment to describe the whole process, but this is the main point.
(mac somemacro (someobj)
`(if ,someobj!field t nil))
When we enter any code at the REPL, it causes three phases to occur: Reading, compilation, and execution.[1]
The read phase processes the ( ) ` , symbols and gets this data structure of cons lists and symbols:
(mac somemacro (someobj)
(quasiquote (if (unquote someobj!field) t nil)))
Note that someobj!field is a single symbol whose name contains an exclamation point character.
At this point you can probably see the problem already. What you may have expected was ((unquote someobj) (quote field)), but what we got was (unquote someobj!field). This is technically because Arc doesn't implement ssyntax at the reader level; instead it uses Racket's reader without modification, and then it processes the ssyntax in the next phase.
Even though the issue should already be clear, I'm going to go through the rest of the process to illustrate macroexpansion.
At this point the compilation phase starts. It expands the (mac ...) macro call, and then it re-processes whatever that macro expands to. As it goes along, at some point it also processes the (quasiquote ...) special form, and it expands the someobj!field syntax. The result of expanding someobj!field is (someobj 'field), and since this isn't a special form or macro, it's compiled as a function call.
The overall result is Racket code. In case it helps show what's going on, I just went to http://tryarc.org/ and ran the following command:
($ (ac '(macro somemacro (someobj) `(if ,someobj!field t nil)) (list)))
This produced a bunch of Racket code, which looks like this if I format it nicely:
Personally, I never think about the raw Racket code. Instead I pretend the result of compilation is Arc code again, just without any macro calls or ssyntax:
Either way, you can see the original (if ... t nil) is still in there somewhere. :)
Finally, this Racket code is executed. It modifies the global environment via Racket's namespace-set-variable-value! and puts a macro there. The macro is simply stored as a tagged value where the tag is 'mac and the content is a function. Then the result of execution is printed to the REPL as "#(tagged mac #<procedure: somemacro>)", and the REPL prompt appears again.
Later on, we execute the following command:
(somemacro oo)
The reader parses this to make this s-expression:
(somemacro oo)
Then the compilation phase starts. It starts to expand the (somemacro ...) macro call. To do this, it invokes the macro implementation we defined earlier. It passes in this list of s-expressions:
(oo)
The macro's implementation is the function that resulted from this Racket code:
Or alternately, in my imagination, it's the result of this macroless Arc code:
(fn (someobj)
(quasiquote
(if (unquote (someobj (quote field)))
t
nil)))
When this function is called, someobj's value is the symbol named "oo". When we try to call the symbol, we get an error.
The compilation phase terminates prematurely, and it displays the error on the console. The execution phase is skipped, since there's nothing to execute. Then the REPL prompt appears again.
I hope this gives people a good picture of the semantics of macroexpansion and ssyntax.
[1] Technically we might add printing and looping phases to get a full Read-Eval-Print-Loop. The eval step of the REPL does compilation followed by execution.
---
As I said above, the confusing point is probably that the reader doesn't give the result that you might expect when it sees ",someobj!field". On the one hand, this is a technical limitation of the fact that Arc uses Racket's reader which doesn't process ssyntax. On the other hand, I think it's debatable if this interpretation of the syntax is better or worse than the alternative.
The ssyntax is a red herring here, since the behavior is the same even if you don't use ssyntax like in my previous comment. I'd also bet that it's the same in common lisp. Just a consequence of macros operating in name space rather than value space. Though this is a kinda subtle consequence of that; I had to run that type example I mentioned before to fully grok what was going on.
How did you figure that out? I found I couldn't macex1 it, because it was already erroring. I guess it's related to when ssexpansion happens in relation to macroexpansion?
The arguments to a macro aren't evaluated. Because of this, someobj has the value of the symbol oo and not the table like the way you wanted. Akkartik's explanation covers the rest of the details.
What happened here was that the type of oo was expanded to sym, and then sym was eval'd in the caller's scope to return a function (thanks to arc being a lisp-1).
The point is, your macro is trying to call a symbol as a function. Instead, this will do what you want:
(mac somemacro (someobj)
`(if (,someobj 'field) t nil))
Yeah I've seen that image too. It's older, and predates the public release of Arc by a few years. The current logo here came even later. Probably just an abortive attempt.
Thank you for the reply and a warm welcome)
I thought it was a chair because of the images on wikipedia page and here http://www.paulgraham.com/arc.html
I got interested in Arc after reading "Hackers & Painters", can't tell anything about my impressions because I don't know much about the language yet, I've discovered it only recently.
I'll definitely learn more about it and then I will have something to say)
Also, you look like you're new to the Arc Forum. Welcome! I've been trying to notice when I see someone new, so we can grow the community. What brings you to Arc? What are your impressions so far?
Interestingly, back when I was first playing around with Arc, I also thought the logo was odd. I designed a new one based around combining the letter A with the concept of an arch (http://www.paulgraham.com/arcfaq.html).
You can see my logo, with a favicon-sized image, here: http://imgur.com/a/RMGu4#sSFHTHt It uses the same colors as the existing one, and has the black border around the outside.
On the off chance anyone developing Arc sees it and wants to use it, that would be awesome, as long as it's properly licensed -- I'm not sure what the proper free license is for things that aren't code. Creative Commons withe the attribution and share-alike clauses? http://creativecommons.org/licenses/by-sa/4.0/
Now that anarki has its first suite of tests using your harness, I've designated all prior tests as "old tests" to encourage us to move away from our patchwork of prior solutions.
Interesting direction to take it. It would be interesting to know how he implemented it, so that he can still consider it to be a lisp. In particular that '#include' syntax sticks out a bit.
I also found it ironic how conflicted he is over its relationship with lisp.
Wart isn't that different from arc, it still shows its roots.
for x 1 (x < 10) ++x
prn x
map prn '(1 2 3 4 5 6 7 8 9 10)
def (f n)
prn n
if (n < 10)
(f n+1)
f.1
Unlike smile it needs those parens around the if condition.
Edit 13 hours later: Ack, I was wrong. Wart would drop the parens just fine!
if n < 10
(f n+1)
I'm not sure I like it, but the design of infix fundamentally supports it by having higher precedence than function calls. If the infix operands grow complex it can get hard to read without parens.
if (function-call n x1 x2 x3) < 10
(f n+1)
# still works, but yuck..
Rather than compare it to arc, I found it tantalizing to think about how I'd implement that syntax. It looks like he's built objects for modules/namespaces, ranges, etc. But he's somehow supporting infix without spaces and also names like print-line. How does it work?! :)
Edit 8 minutes later: Also, the square brackets around the call to [f 1] are strange. If they're mandatory, there's something there I don't follow.
It's not packaged up, all the internals are hanging out, some assembly is required. But it enumerates the scenarios I considered so that others can understand precisely what I was trying to achieve and hopefully build on it if their needs are concordant.