Re: [racket-dev] When is it safe to not rename a runtime value in a macro?

2012-08-25 Thread Neil Toronto
Investigated a bit today. I wrote a function that optimizes kernel 
syntax, making these kinds of replacements:


  (let-values ([(x:id)  y:id]) body)
->
  (let-syntaxes+values ([(x)  (make-rename-transformer #'y)]) () body)

and then fully expanding the code again. It also does simple beta 
reduction, by changing ((lambda (x ...) body ...) e ...) into a 
`let-values'. I've managed to shave 1/4 the runtime off simple things 
like this:


  (let ([y 4])
((lambda (x)
   (let ([z y])
 (+ x z)))
 5))

It doesn't correctly handle variables that get mutated, but having it 
search their lexical scope for `set!' should do it. I think.


It hasn't been too bad so far.

Neil ⊥

On 08/25/2012 11:03 AM, Matthias Felleisen wrote:


It's the wrong way to go. Let's investigate more before we jump to conclusions.


On Aug 25, 2012, at 12:54 PM, Neil Toronto wrote:


Then I suppose the obvious thing to do is move the optimizations up to the 
macro level? :)

It's also for debugging, by the way. Having to mentally or manually substitute 
bindings to understand fully expanded code annoys me and wastes time.

Neil ⊥

On 08/25/2012 10:24 AM, Robby Findler wrote:

This is definitely a macro writer bill of rights situation. Too bad
that TR's optimizer cannot take advantage of all these kinds of things
that are already happening in the optimizer one level down.

Robby

On Sat, Aug 25, 2012 at 11:19 AM, Neil Toronto  wrote:

A lot of macros start by renaming some syntax that's assumed to eventually
represent a runtime value, like the `or' macro does:


(syntax->datum (expand-syntax #'(or #t #f)))

'(let-values (((or-part) '#t)) (if or-part or-part '#f))

But it's not always a good thing, particularly when the output will be
processed by another macro, and parts will be tested using an `identifier=?'
function. For example, my `inline-sort' takes `<' as an argument. So

   (inline-sort < a b)

expands to

   (let ([lt? <] [temp1 a] [temp2 b])
 (if (lt? temp1 temp2) (values temp1 temp2) (values temp2 temp1)))

Well, it did at first. When I discovered that Typed Racket's optimizer would
never detect that `lt?' is actually `<' and replace it with `unsafe-fl<', I
altered the macro to detect when the `<' is an identifier, and not rename it
with a `let'.

I know that I should assert my rights under the Macro Bill. But I like to
program defensively. So what's safe to not rename? I think the following
are:

symbol
number
string
bytes
null
character
regexp
prefab struct key

Also, should I ever have to intern syntax that's one of these kinds of
things?

Neil ⊥

_
  Racket Developers list:
  http://lists.racket-lang.org/dev


_
Racket Developers list:
http://lists.racket-lang.org/dev




_
 Racket Developers list:
 http://lists.racket-lang.org/dev


Re: [racket-dev] When is it safe to not rename a runtime value in a macro?

2012-08-25 Thread Matthias Felleisen

On Aug 25, 2012, at 3:56 PM, Ryan Culpepper wrote:

> In other words, a macro's subexpressions should be used linearly (as in 
> "linear types"). Putting an expression in the macro's result in an expression 
> context counts as a use. (But putting it in the result in a quoted context 
> doesn't.) Calling 'local-expand' or 'syntax-local-expand-expression' on it 
> also counts as a use, but it gives back another linearly-restricted 
> expression. (The same applies to definitions; I should really say all "forms" 
> should be used linearly.)

Are you going to write up a tool and/or a macro-linear-type system that checks 
such things? ICFP is waiting -- Matthias



smime.p7s
Description: S/MIME cryptographic signature
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] When is it safe to not rename a runtime value in a macro?

2012-08-25 Thread Eli Barzilay
7 hours ago, Matthias Felleisen wrote:
> 
> It's the wrong way to go. Let's investigate more before we jump to
> conclusions.

Would it work if let-bound (etc) ids could have some property tracing
them to the expressions they were bound to?

-- 
  ((lambda (x) (x x)) (lambda (x) (x x)))  Eli Barzilay:
http://barzilay.org/   Maze is Life!
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] When is it safe to not rename a runtime value in a macro?

2012-08-25 Thread Eli Barzilay
6 hours ago, Ryan Culpepper wrote:
> 
> In Racket, literal data carry lexical information just like
> identifiers.  When a literal datum is used as an expression, the
> macro expander synthesizes a '#%datum' identifier that determines
> what to do with the literal. The Racket '#%datum' macro just expands
> into a 'quote' expression if the datum is not a keyword.

[And it's not just an academic exerice: I have an LC-like language in
my class where everything is an identifier.  (It makes a nice point
about really having nothing except for lambdas, applications, and
identifiers.)]

-- 
  ((lambda (x) (x x)) (lambda (x) (x x)))  Eli Barzilay:
http://barzilay.org/   Maze is Life!
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] When is it safe to not rename a runtime value in a macro?

2012-08-25 Thread Ryan Culpepper

On 08/25/2012 01:57 PM, Neil Toronto wrote:

On 08/25/2012 11:33 AM, Ryan Culpepper wrote:

On 08/25/2012 01:08 PM, Neil Toronto wrote:

A number can expand to an arbitrary expression? How?

And what do you mean by "the '#%datum' macro associated with them"?
Applied to them?


 > (let-syntax ([#%datum (lambda (stx) #'(printf "hello\n"))]) 5)
hello

In Racket, literal data carry lexical information just like identifiers.
When a literal datum is used as an expression, the macro expander
synthesizes a '#%datum' identifier that determines what to do with the
literal. The Racket '#%datum' macro just expands into a 'quote'
expression if the datum is not a keyword.

The implicit '#%app' syntax works similarly, except it takes its lexical
context from the pair that represents the application.


Holy heck I had no idea. That's awesome and scary.

So this is what I have now:

(define skip-ids
   (syntax->list #'(+ - * / < > <= >= = min max)))

(define (skip-binding? e-stx)
   (let ([e-stx  (local-expand e-stx 'expression #f)])
 (and (identifier? e-stx)
  (findf (λ (skip-id) (free-identifier=? skip-id e-stx))
 skip-ids


I would have called it safe before today, but I knew fewer awesome and
scary things. Does it look safe to you?


In this case you can get rid of the 'local-expand', since you're only 
looking for references to particular variables.


If you do keep the 'local-expand', you should use the result in the code 
your macro produces so that the expression isn't expanded multiple 
times. For example:


(define-syntax (m stx)
  (syntax-case stx ()
[(m e stuff ...)
 (let ([ee (local-expand #'e 'expression #f)])
   (if (and (identifier? ee)
(for/or ([skip-id skip-ids])
  (free-identifier=? ee skip-id)))
   #`(real-m #,ee stuff ...)
   #`(let ([tmp #,ee])
   (real-m tmp stuff ...]))

Depending on exactly what you're doing, you might want an empty stop 
list instead of #f. Or you might want to use 
'syntax-local-expand-expression' instead so that the expander doesn't 
have to retraverse the expanded expression.


--

In other words, a macro's subexpressions should be used linearly (as in 
"linear types"). Putting an expression in the macro's result in an 
expression context counts as a use. (But putting it in the result in a 
quoted context doesn't.) Calling 'local-expand' or 
'syntax-local-expand-expression' on it also counts as a use, but it 
gives back another linearly-restricted expression. (The same applies to 
definitions; I should really say all "forms" should be used linearly.)


Ryan

_
 Racket Developers list:
 http://lists.racket-lang.org/dev


Re: [racket-dev] When is it safe to not rename a runtime value in a macro?

2012-08-25 Thread Neil Toronto

On 08/25/2012 11:33 AM, Ryan Culpepper wrote:

On 08/25/2012 01:08 PM, Neil Toronto wrote:

A number can expand to an arbitrary expression? How?

And what do you mean by "the '#%datum' macro associated with them"?
Applied to them?


 > (let-syntax ([#%datum (lambda (stx) #'(printf "hello\n"))]) 5)
hello

In Racket, literal data carry lexical information just like identifiers.
When a literal datum is used as an expression, the macro expander
synthesizes a '#%datum' identifier that determines what to do with the
literal. The Racket '#%datum' macro just expands into a 'quote'
expression if the datum is not a keyword.

The implicit '#%app' syntax works similarly, except it takes its lexical
context from the pair that represents the application.


Holy heck I had no idea. That's awesome and scary.

So this is what I have now:

(define skip-ids
  (syntax->list #'(+ - * / < > <= >= = min max)))

(define (skip-binding? e-stx)
  (let ([e-stx  (local-expand e-stx 'expression #f)])
(and (identifier? e-stx)
 (findf (λ (skip-id) (free-identifier=? skip-id e-stx))
skip-ids


I would have called it safe before today, but I knew fewer awesome and 
scary things. Does it look safe to you?


Neil ⊥

_
 Racket Developers list:
 http://lists.racket-lang.org/dev


Re: [racket-dev] When is it safe to not rename a runtime value in a macro?

2012-08-25 Thread Ryan Culpepper

On 08/25/2012 01:08 PM, Neil Toronto wrote:

On 08/25/2012 10:53 AM, Ryan Culpepper wrote:

On 08/25/2012 12:19 PM, Neil Toronto wrote:
I've reordered these a bit:


number
string
bytes
character
regexp


In other words, "literal data". But did you check that the '#%datum'
macro associated with them has the standard meaning? If not, they could
expand into arbitrary expressions (possibly with side effects)!


A number can expand to an arbitrary expression? How?

And what do you mean by "the '#%datum' macro associated with them"?
Applied to them?


> (let-syntax ([#%datum (lambda (stx) #'(printf "hello\n"))]) 5)
hello

In Racket, literal data carry lexical information just like identifiers. 
When a literal datum is used as an expression, the macro expander 
synthesizes a '#%datum' identifier that determines what to do with the 
literal. The Racket '#%datum' macro just expands into a 'quote' 
expression if the datum is not a keyword.


The implicit '#%app' syntax works similarly, except it takes its lexical 
context from the pair that represents the application.


Ryan

_
 Racket Developers list:
 http://lists.racket-lang.org/dev


Re: [racket-dev] When is it safe to not rename a runtime value in a macro?

2012-08-25 Thread Matthias Felleisen

It's the wrong way to go. Let's investigate more before we jump to conclusions. 


On Aug 25, 2012, at 12:54 PM, Neil Toronto wrote:

> Then I suppose the obvious thing to do is move the optimizations up to the 
> macro level? :)
> 
> It's also for debugging, by the way. Having to mentally or manually 
> substitute bindings to understand fully expanded code annoys me and wastes 
> time.
> 
> Neil ⊥
> 
> On 08/25/2012 10:24 AM, Robby Findler wrote:
>> This is definitely a macro writer bill of rights situation. Too bad
>> that TR's optimizer cannot take advantage of all these kinds of things
>> that are already happening in the optimizer one level down.
>> 
>> Robby
>> 
>> On Sat, Aug 25, 2012 at 11:19 AM, Neil Toronto  
>> wrote:
>>> A lot of macros start by renaming some syntax that's assumed to eventually
>>> represent a runtime value, like the `or' macro does:
>>> 
 (syntax->datum (expand-syntax #'(or #t #f)))
>>> '(let-values (((or-part) '#t)) (if or-part or-part '#f))
>>> 
>>> But it's not always a good thing, particularly when the output will be
>>> processed by another macro, and parts will be tested using an `identifier=?'
>>> function. For example, my `inline-sort' takes `<' as an argument. So
>>> 
>>>   (inline-sort < a b)
>>> 
>>> expands to
>>> 
>>>   (let ([lt? <] [temp1 a] [temp2 b])
>>> (if (lt? temp1 temp2) (values temp1 temp2) (values temp2 temp1)))
>>> 
>>> Well, it did at first. When I discovered that Typed Racket's optimizer would
>>> never detect that `lt?' is actually `<' and replace it with `unsafe-fl<', I
>>> altered the macro to detect when the `<' is an identifier, and not rename it
>>> with a `let'.
>>> 
>>> I know that I should assert my rights under the Macro Bill. But I like to
>>> program defensively. So what's safe to not rename? I think the following
>>> are:
>>> 
>>> symbol
>>> number
>>> string
>>> bytes
>>> null
>>> character
>>> regexp
>>> prefab struct key
>>> 
>>> Also, should I ever have to intern syntax that's one of these kinds of
>>> things?
>>> 
>>> Neil ⊥
>>> 
>>> _
>>>  Racket Developers list:
>>>  http://lists.racket-lang.org/dev
> 
> _
> Racket Developers list:
> http://lists.racket-lang.org/dev



smime.p7s
Description: S/MIME cryptographic signature
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] When is it safe to not rename a runtime value in a macro?

2012-08-25 Thread Neil Toronto

On 08/25/2012 10:53 AM, Ryan Culpepper wrote:

On 08/25/2012 12:19 PM, Neil Toronto wrote:
I've reordered these a bit:


number
string
bytes
character
regexp


In other words, "literal data". But did you check that the '#%datum'
macro associated with them has the standard meaning? If not, they could
expand into arbitrary expressions (possibly with side effects)!


A number can expand to an arbitrary expression? How?

And what do you mean by "the '#%datum' macro associated with them"? 
Applied to them?



symbol


Do you mean identifier, as in "it's just a variable reference"? But it
could be an identifier macro. Or it could be a variable that other parts
of the code could concurrently mutate. For example, suppose 'match'
expanded less cautiously than it actually does:

   (match x [(cons a b) a])
   =>
   (if (pair? x) (unsafe-car x) (match-error ))

Now suppose that x is a module-level variable that some other thread
mutates between the 'pair?' check and the 'unsafe-car'.


Right. Typed Racket would actually catch these at compile time, but 
mutation would still break my macros. *sigh*



If you must do such things, the safest way in general is to fully
local-expand the expression you want to analyze; that gives you
something with a known grammar. Now it's feasible to identify literal
data: it's any 'quote' expression. You don't have to worry about
identifier macros, but the 'set!' danger remains for any variables that
you don't completely control the scope of.

In your specific case, it would also be safe to check whether the
comparison expression is an identifier free-identifier=? to one of a
fixed list of known (immutable) variables; if so, it's safe to duplicate.


I think I'll have to go that route.

Thanks for the explanations!

Neil ⊥

_
 Racket Developers list:
 http://lists.racket-lang.org/dev


Re: [racket-dev] When is it safe to not rename a runtime value in a macro?

2012-08-25 Thread Neil Toronto
Then I suppose the obvious thing to do is move the optimizations up to 
the macro level? :)


It's also for debugging, by the way. Having to mentally or manually 
substitute bindings to understand fully expanded code annoys me and 
wastes time.


Neil ⊥

On 08/25/2012 10:24 AM, Robby Findler wrote:

This is definitely a macro writer bill of rights situation. Too bad
that TR's optimizer cannot take advantage of all these kinds of things
that are already happening in the optimizer one level down.

Robby

On Sat, Aug 25, 2012 at 11:19 AM, Neil Toronto  wrote:

A lot of macros start by renaming some syntax that's assumed to eventually
represent a runtime value, like the `or' macro does:


(syntax->datum (expand-syntax #'(or #t #f)))

'(let-values (((or-part) '#t)) (if or-part or-part '#f))

But it's not always a good thing, particularly when the output will be
processed by another macro, and parts will be tested using an `identifier=?'
function. For example, my `inline-sort' takes `<' as an argument. So

   (inline-sort < a b)

expands to

   (let ([lt? <] [temp1 a] [temp2 b])
 (if (lt? temp1 temp2) (values temp1 temp2) (values temp2 temp1)))

Well, it did at first. When I discovered that Typed Racket's optimizer would
never detect that `lt?' is actually `<' and replace it with `unsafe-fl<', I
altered the macro to detect when the `<' is an identifier, and not rename it
with a `let'.

I know that I should assert my rights under the Macro Bill. But I like to
program defensively. So what's safe to not rename? I think the following
are:

symbol
number
string
bytes
null
character
regexp
prefab struct key

Also, should I ever have to intern syntax that's one of these kinds of
things?

Neil ⊥

_
  Racket Developers list:
  http://lists.racket-lang.org/dev


_
 Racket Developers list:
 http://lists.racket-lang.org/dev


Re: [racket-dev] When is it safe to not rename a runtime value in a macro?

2012-08-25 Thread Ryan Culpepper

On 08/25/2012 12:19 PM, Neil Toronto wrote:

A lot of macros start by renaming some syntax that's assumed to
eventually represent a runtime value, like the `or' macro does:

 > (syntax->datum (expand-syntax #'(or #t #f)))
'(let-values (((or-part) '#t)) (if or-part or-part '#f))

But it's not always a good thing, particularly when the output will be
processed by another macro, and parts will be tested using an
`identifier=?' function. For example, my `inline-sort' takes `<' as an
argument. So

   (inline-sort < a b)

expands to

   (let ([lt? <] [temp1 a] [temp2 b])
 (if (lt? temp1 temp2) (values temp1 temp2) (values temp2 temp1)))

Well, it did at first. When I discovered that Typed Racket's optimizer
would never detect that `lt?' is actually `<' and replace it with
`unsafe-fl<', I altered the macro to detect when the `<' is an
identifier, and not rename it with a `let'.


Is it feasible to make the TR optimizer smarter about this? That would 
be the best solution.



I know that I should assert my rights under the Macro Bill. But I like
to program defensively. So what's safe to not rename? I think the
following are:


I've reordered these a bit:


number
string
bytes
character
regexp


In other words, "literal data". But did you check that the '#%datum' 
macro associated with them has the standard meaning? If not, they could 
expand into arbitrary expressions (possibly with side effects)!



symbol


Do you mean identifier, as in "it's just a variable reference"? But it 
could be an identifier macro. Or it could be a variable that other parts 
of the code could concurrently mutate. For example, suppose 'match' 
expanded less cautiously than it actually does:


  (match x [(cons a b) a])
  =>
  (if (pair? x) (unsafe-car x) (match-error ))

Now suppose that x is a module-level variable that some other thread 
mutates between the 'pair?' check and the 'unsafe-car'.



null
prefab struct key


I don't know what you mean by these in this context. Maybe 'quote' 
expressions containing them?


--

If you must do such things, the safest way in general is to fully 
local-expand the expression you want to analyze; that gives you 
something with a known grammar. Now it's feasible to identify literal 
data: it's any 'quote' expression. You don't have to worry about 
identifier macros, but the 'set!' danger remains for any variables that 
you don't completely control the scope of.


In your specific case, it would also be safe to check whether the 
comparison expression is an identifier free-identifier=? to one of a 
fixed list of known (immutable) variables; if so, it's safe to duplicate.



Also, should I ever have to intern syntax that's one of these kinds of
things?


Do you mean intern the data? IIUC, yes: the reader interns literal data, 
but macros are free to introduce non-interned literal data. (It will 
probably get interned again when the compiled form is loaded from zo, 
but there's a period during the expansion of the enclosing module when 
it won't be interned.)


Ryan

_
 Racket Developers list:
 http://lists.racket-lang.org/dev


Re: [racket-dev] When is it safe to not rename a runtime value in a macro?

2012-08-25 Thread Robby Findler
This is definitely a macro writer bill of rights situation. Too bad
that TR's optimizer cannot take advantage of all these kinds of things
that are already happening in the optimizer one level down.

Robby

On Sat, Aug 25, 2012 at 11:19 AM, Neil Toronto  wrote:
> A lot of macros start by renaming some syntax that's assumed to eventually
> represent a runtime value, like the `or' macro does:
>
>> (syntax->datum (expand-syntax #'(or #t #f)))
> '(let-values (((or-part) '#t)) (if or-part or-part '#f))
>
> But it's not always a good thing, particularly when the output will be
> processed by another macro, and parts will be tested using an `identifier=?'
> function. For example, my `inline-sort' takes `<' as an argument. So
>
>   (inline-sort < a b)
>
> expands to
>
>   (let ([lt? <] [temp1 a] [temp2 b])
> (if (lt? temp1 temp2) (values temp1 temp2) (values temp2 temp1)))
>
> Well, it did at first. When I discovered that Typed Racket's optimizer would
> never detect that `lt?' is actually `<' and replace it with `unsafe-fl<', I
> altered the macro to detect when the `<' is an identifier, and not rename it
> with a `let'.
>
> I know that I should assert my rights under the Macro Bill. But I like to
> program defensively. So what's safe to not rename? I think the following
> are:
>
> symbol
> number
> string
> bytes
> null
> character
> regexp
> prefab struct key
>
> Also, should I ever have to intern syntax that's one of these kinds of
> things?
>
> Neil ⊥
>
> _
>  Racket Developers list:
>  http://lists.racket-lang.org/dev

_
  Racket Developers list:
  http://lists.racket-lang.org/dev


[racket-dev] When is it safe to not rename a runtime value in a macro?

2012-08-25 Thread Neil Toronto
A lot of macros start by renaming some syntax that's assumed to 
eventually represent a runtime value, like the `or' macro does:


> (syntax->datum (expand-syntax #'(or #t #f)))
'(let-values (((or-part) '#t)) (if or-part or-part '#f))

But it's not always a good thing, particularly when the output will be 
processed by another macro, and parts will be tested using an 
`identifier=?' function. For example, my `inline-sort' takes `<' as an 
argument. So


  (inline-sort < a b)

expands to

  (let ([lt? <] [temp1 a] [temp2 b])
(if (lt? temp1 temp2) (values temp1 temp2) (values temp2 temp1)))

Well, it did at first. When I discovered that Typed Racket's optimizer 
would never detect that `lt?' is actually `<' and replace it with 
`unsafe-fl<', I altered the macro to detect when the `<' is an 
identifier, and not rename it with a `let'.


I know that I should assert my rights under the Macro Bill. But I like 
to program defensively. So what's safe to not rename? I think the 
following are:


symbol
number
string
bytes
null
character
regexp
prefab struct key

Also, should I ever have to intern syntax that's one of these kinds of 
things?


Neil ⊥

_
 Racket Developers list:
 http://lists.racket-lang.org/dev