[plt-scheme] On hygiene and trust
On Wed, Jul 8, 2009 at 5:41 PM, Abdulaziz Ghuloum<aghuloum at gmail.com> wrote:
>
> On Jul 8, 2009, at 6:04 PM, Joe Marshall wrote:
>
>> On Wed, Jul 8, 2009 at 7:31 AM, Abdulaziz Ghuloum<aghuloum at gmail.com>
>> wrote:
>>>
>>> I don't agree. Show me a painful simple use. Pick any simple
>>> macro you want: let, let*, or, and, cond, case, or any other
>>> macro of your choice to show the pain.
>>
>> This came up the other day. Transform something like this:
>>
>> (define-event foo bar (arg1 arg2 ...)
>> (form1)
>> (form2 ...) etc.)
>>
>> into something like this:
>>
>> (define (foo$bar arg1 arg2 ...)
>> (form1)
>> (form2 ...) etc.)
>
> I don't see the pain caused by "syntax-case", and maybe I don't
> understand the problem you're having. Can you please write your
> macro in syntax-case because my attempt below probably does not
> do what you had in mind.
>
> (define-syntax define-event
> (lambda (stx)
> (define (concat x y) --- fill in the blank ---)
> (syntax-case stx ()
> [(_ foo bar (arg1 arg2 ...)
> (form1)
> (form2 ...) etc.)
> #`(define (#,(concat #'foo #'bar) arg1 arg2 ...)
> (form1)
> (form2 ...) etc.)])))
(define-syntax define-event
(lambda (stx)
(define (concat . x)
(string->symbol (apply string-append (map symbol->string x))))
(syntax-case stx ()
[(_ foo bar arguments form1 . body)
#`(define (#,(concat #'foo '$ #'bar) . arguments)
form1 . body)])))
(define-event foo bar (x y) (list x y))
collects\scheme\private\map.ss:22:17: symbol->string: expects argument
of type <symbol>; given #<syntax:3:16>
This is what usually happens when I try to use syntax-case. I end up getting
syntax objects where I want symbols, or symbols where I want syntax objects,
or syntax object closed in the wrong scope. Then I end up trying permutations
of sharps, backticks, commas, and quotes until it eventually works.
Yes, it is laziness on my part. I ought to re-read the documentation, and if I
had practice at it, I'd be ok, but I don't write all that many macros, so when
I do, I inevitably have to re-learn it.
>
>
>>>> defmacro is really easy to use and understand, but isn't hygienic.
>>>
>>> I don't agree that defmacro is easy to use without a pattern
>>> matching facility. Again, write the example that you provide
>>> (above) using defmacro; I doubt it will be simpler or easier
>>> or more robust, or anything.
>>
>> Do you consider backquote a pattern matching facility?
>
> Not really.
>
>> ;; Common lisp version of named-let
>> (defmacro named-let (name bindings &body body)
>> `(LABELS ((,name ,(map 'list #'car bindings) , at body))
>> (,name ,@(map 'list #'cadr bindings))))
>
> This code has a bug that's not related to hygiene but to the scope
> of the "name" identifier.
Yeah. it should be more like this:
(defmacro named-let (name bindings &body body)
`(funcall (LABELS ((,name ,(map list #'car bindings) , at body))
(function name)) ,@(map 'list #'cadr bindings)))
But the compiler generates much worse code for this. The scoping
issue is a minor issue.
> But either way, I don't see that as simpler
> or easier to use than, say, the following (exhibiting the same bug):
>
> (define-syntax-rule
> (named-let name ((lhs* rhs*) ...) b b* ...)
> (letrec ((name (lambda (lhs* ...) b b* ...)))
> (name rhs* ...)))
>
> It looks like named-let is a trivial macro that can be handled
> trivially in any macro system, so, it does not really show that
> "defmacro is really easy to use and understand". As the complexity
> of the macro increases, doesn't it just cause more littering with
> all of these map this and map that and splice this and that?
Yes, but I don't think it is any more complex than the ellipses.
> PS. I'm just trying to understand your position, since I was pretty
> surprised that *you* find defmacro style superior to anything else
> in scheme (modulo hygiene as you said).
I didn't say that. I said it was easier to understand what the defmacro
form is doing to the code. The transformation from list-structure to
different list-structure is pretty straightforward. Syntax objects are
more opaque: #<syntax:3:16>
What is that? An identifier? Which one? (A quote from the King James
Bible, book of Syntax, Chapter 3, verse 16?)
I can't `mapcar' over a syntax object.
And when I go in the other direction, I have the symbol `foo' and I wish
to create some code that uses it, I have to transform it into a syntax
object with the appropriate scope.
> I mean, you know macros,
> and none of this is new to you, but do you really find manipulating
> S-expressions that much easier and simpler than manipulating syntax
> objects? Or is it something else?
I do find list structure easier to manipulate that syntax objects. Syntax
objects *include* everything that is in the list structure, and then add some
more stuff. Furthermore, syntax objects don't have the incredibly rich
library of list manipulation functions.
That said, I don't *prefer* defmacro style macros. They are buggy, and
while it is obvious to see *what* they do to the code, it isn't obvious how
to make them work correctly.
On the other hand, I don't much like syntax-case. It is much more
complicated to use, and I see it used too often.
I want something else. I'm not sure what, though.
--
~jrm