<div dir="ltr">On Thu, May 30, 2013 at 12:25 PM, Eric Dobson <span dir="ltr"><<a href="mailto:eric.n.dobson@gmail.com" target="_blank">eric.n.dobson@gmail.com</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Why do literal-sets have to be unhygienic? I expected them to work<br>
like literal lists which you say are hygienic. Also literal-sets are<br>
not documented as being unhygienic, which was the confusing part.<br></blockquote><div><br></div><div>Literal sets are hygienic in the informal sense of "follow a disciplined notion of binding structure". They are not hygienic in the formal sense of Scheme and Racket expansion wherein names derive their scope from where they appear in the source. Specifically, when you use a literal set, you do not write down the names in the set, yet they are scoped as if you wrote them right there in your program. Which is what you want -- to use those names in the current scope -- but is not hygienic, by the strict definition. Anything where you "store" names and pull them out later -- module exports, unit signatures, literal sets, and other similar tools -- is necessarily unhygienic. Using them in surface syntax is relatively straightforward; using them in macros is tricky, because these tools have to introduce the stored names into some lexical context for you to use, and with a macro that could be either the macro's context or the macro user's context.<br>
</div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
In my example 2 both the literals in the literal-list and the ids used<br>
to match the syntax have the same marks, so it is very unintuitive<br>
that the lexical context of the literal-set name should matter. Also<br>
can literal sets be used to abstract over identifiers with different<br>
lexical contexts, intuitively since other forms can do that I would<br>
expect that they should be able to, but given that its unhygienic I'm<br>
not so sure now.<br></blockquote><div><br></div><div>Because literal-sets can be used in any context, the names used in the literal set are used in the context of the reference to the literal set. So if a macro injects the name of the literal set to a syntax-parse expression, the macro needs to determine whether that literal set is used in the macro's context or the macro user's context. Otherwise it could be difficult to use the names in the macro itself. Hence the #:at option, which lets macros specify the context "at" which the literal set is used, if it's different from the context naming the literal set.<br>
</div><div><br></div><div>The short, short version: use the #:at option if your macro uses literal sets "on behalf of" the user.<br><br></div><div>The syntax-parse documentation could probably be more explicit about how literals in literal sets derive their context; I do not envy Ryan the task of writing that up, because I'm not sure how to make it 100% clear myself, as my ramblings above may show.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Thu, May 30, 2013 at 3:49 AM, Ryan Culpepper <<a href="mailto:ryanc@ccs.neu.edu">ryanc@ccs.neu.edu</a>> wrote:<br>
<div class="HOEnZb"><div class="h5">
> On 05/29/2013 03:30 AM, Eric Dobson wrote:<br>
>><br>
>> I was writing a macro that generated a literal-set and ran into some<br>
>> confusing behavior which I have distilled to the following program.<br>
>><br>
>> #lang racket<br>
>> (require syntax/parse<br>
>> (for-syntax syntax/parse))<br>
>><br>
>><br>
>> (define-syntax (define-ls1 stx)<br>
>> (syntax-parse stx<br>
>> ((_ name:id (lit:id ...))<br>
>> #'(define-literal-set name (lit ...)))))<br>
>><br>
>> (define-ls1 ls1 (+))<br>
>> (define-syntax-class sc1<br>
>> #:literal-sets (ls1)<br>
>> (pattern +))<br>
>><br>
>> (for/list ((x (list #'+ #'*)))<br>
>> (syntax-parse x<br>
>> (x:sc1 #t)<br>
>> (_ #f)))<br>
>><br>
>><br>
>> (define-syntax (define-sc2 stx)<br>
>> (syntax-parse stx<br>
>> ((_ name:id (lit:id ...))<br>
>> #'(begin<br>
>> (define-literal-set inner (lit ...))<br>
>> (define-syntax-class name<br>
>> #:literal-sets (inner)<br>
>> (pattern lit) ...)))))<br>
>><br>
>> (define-sc2 sc2 (+))<br>
>> (for/list ((x (list #'+ #'*)))<br>
>> (syntax-parse x<br>
>> (x:sc2 #t)<br>
>> (_ #f)))<br>
>><br>
>> (define-syntax (define-sc3 stx)<br>
>> (syntax-parse stx<br>
>> ((_ name:id inner:id (lit:id ...))<br>
>> #'(begin<br>
>> (define-literal-set inner (lit ...))<br>
>> (define-syntax-class name<br>
>> #:literal-sets (inner)<br>
>> (pattern lit) ...)))))<br>
>><br>
>> (define-sc3 sc3 inner3 (+))<br>
>> (for/list ((x (list #'+ #'*)))<br>
>> (syntax-parse x<br>
>> (x:sc3 #t)<br>
>> (_ #f)))<br>
>><br>
>><br>
>> (define-syntax (define-sc4 stx)<br>
>> (syntax-parse stx<br>
>> ((_ name:id (lit:id ...))<br>
>> #'(begin<br>
>> (define-literal-set inner (lit ...))<br>
>> (define-syntax-class name<br>
>> #:literal-sets ((inner #:at name))<br>
>> (pattern lit) ...)))))<br>
>><br>
>> (define-sc4 sc4 (+))<br>
>> (for/list ((x (list #'+ #'*)))<br>
>> (syntax-parse x<br>
>> (x:sc4 #t)<br>
>> (_ #f)))<br>
>><br>
>> This produces the output:<br>
>> '(#t #f)<br>
>> '(#t #t)<br>
>> '(#t #f)<br>
>> '(#t #f)<br>
>><br>
>> I would have expected the second one to return '(#t #f) like the first<br>
>> but it doesn't.<br>
><br>
><br>
> The issue is how syntax-parse decides whether an identifier in a pattern is<br>
> a pattern variable or a literal. Let's take the simple case, where we have<br>
> just a literals list. From the standpoint of hygiene, the literals list is<br>
> "binding-like" because it sets the interpretation for "references" in the<br>
> patterns. That means the relevant comparison is bound-identifier=? (like all<br>
> binding forms), and that means that at a minimum if you want an identifier<br>
> in a pattern to be considered a literal, it must have the same marks as the<br>
> corresponding identifier in the literals list. Consider the following<br>
> program:<br>
><br>
> (define-syntax-rule<br>
> (define-syntax-rule/arith (macro . pattern) template)<br>
> (define-syntax macro<br>
> (syntax-rules (+ - * /)<br>
> [(macro . pattern) template])))<br>
><br>
> (define-syntax-rule/arith (sum-left-arg (+ x y)) x)<br>
><br>
> One might expect sum-left-arg to raise a syntax error if given a term with<br>
> something other than + in operator position. But in fact:<br>
><br>
> (sum-left-arg (* 1 2))<br>
> ;; => 1<br>
><br>
> The reason is because the expansion of define-syntax-rule/arith puts marks<br>
> on the + in the literals list. So only +'s with the same mark in the pattern<br>
> are considered literals; all others are pattern variables. In particular,<br>
> the + in the pattern in the definition of sum-left-arg is unmarked, so it's<br>
> a pattern variable.<br>
><br>
> Now back to literal sets. A #:literal-sets clause is an essentially like an<br>
> unhygienic binding form. The identifiers it "binds" must be given some<br>
> lexical context; it defaults to the lexical context of the literal set name.<br>
> In define-sc2 from your example, that is inner, which is introduced by the<br>
> macro and thus has a mark on it. So it's just like you had a literals list<br>
> consisting of a marked +. But the + in the pattern is unmarked, since it<br>
> comes from the original program (via the lit pattern variable). They don't<br>
> match, so the identifier in the pattern is interpreted as a pattern<br>
> variable.<br>
><br>
><br>
>> The third and fourth are ways to get it to, but I'm<br>
>><br>
>> not sure why they work. The third seems to show that the meaning of<br>
>> how a literal set binds variables depends on the context of the<br>
>> literal-set name and not the actual literals.<br>
><br>
><br>
> In define-sc3, inner also comes from the original program, so it's unmarked,<br>
> so the literals consist of an unmarked +, which matches the + in the<br>
> pattern.<br>
><br>
><br>
>> The fourth way uses #:at<br>
>><br>
>> which is documented as being useful to macros, but not much else. Can<br>
>> someone explain how literal-sets are supposed to determine whether or<br>
>> not a variable in the pattern is treated as a literal or as a pattern<br>
>> variable?<br>
><br>
><br>
> An #:at clause changes the lexical context given to literals. In define-sc4,<br>
> inner is back to being marked, but that doesn't matter, because the literals<br>
> are given the lexical context of the syntax bound to name. In the example,<br>
> that's sc4, which comes from the macro use and is thus unmarked.<br>
><br>
> All unhygienic binding forms have similar difficulties. Macros that expand<br>
> into require forms are another common source of confusion.<br>
><br>
> Ryan<br>
><br>
____________________<br>
Racket Users list:<br>
<a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
<br>
</div></div></blockquote></div><br></div></div>