guile-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Pure (side-effect-free) calls into c/c++?


From: Linas Vepstas
Subject: Re: Pure (side-effect-free) calls into c/c++?
Date: Sat, 11 Jan 2020 20:15:32 -0600

Thanks Taylan, gmail is on the fritz lately and doesn't show replies until
after I post; let me read what you wrote and ponder. ~~~

On Sat, Jan 11, 2020 at 3:56 PM Taylan Kammer <address@hidden>
wrote:

> On 11.01.2020 19:52, Linas Vepstas wrote:
> > Or, thinking aloud a bit: boxes and symbols....
> >
> > So, for example, if I was able to tell apart calls (f 42) from calls (f
> x)
> > where x is a "symbol" (or "variable", *see below*) referencing an
> integer,
> > then, for the former case, I could create a new symbol (in guile) and
> > attach it to a box, fill that box with whatever (f 42) would have
> returned.
> > Thence-forward, any call site in the guile code that had (f 42) in it
> would
> > get replaced by the symbol (or the unboxed value)...
> >
> > At the moment, I don't know how to tell apart 42, the literal number,
> from
> > x, a symbol that references a number. (Somehow, I can't make symbol? work
> > ...)  I also don't know how to "edit" the call site (the cell, the box?)
> > that has (f 42) as the call-target, and replace it by a constant (or a
> > boxed constant).
> >
> > But my naive thinking fails:
> > (define x 0)
> > (symbol? x)  => #f
> > (variable? x) => #f
> >
> > So I guess that x is not a symbol, from the guile point of view!?  This
> is
> > .. confusing. What is x, then, if not a symbol?
>
> The issue here is that the expression "(symbol? x)" first evaluates the
> expressions "symbol?" and "x" and then uses their values to go on.  So
> it ends up being:
>
>     (<value-of-symbol?> <value-of-x>)
>
> So by the time the procedure behind "symbol?" is called, it neither
> knows that it was called "symbol?" nor does it know that the value it
> received, i.e. the integer 0, came from a variable called "x".
>
> What you want to do is delve down to the macro layer so to say, by using
> "define-syntax" and ideally "syntax-case".
>
> Here's a demonstration:
>
>   (define-syntax symbol-syntax?
>     (lambda (stx)
>       (syntax-case stx ()
>         ((_ x)
>          (if (symbol? (syntax->datum #'x))
>              #'(display "yep\n")
>              #'(display "nope\n"))))))
>
>   scheme> (symbol-syntax? blah)
>   yep
>   scheme> (symbol-syntax? (blah))
>   nope
>
> What happens here is the following.  Going through it part by part.
>
>   (define-syntax symbol-syntax?
>     (lambda (stx)
>       ...
>
> You register a procedure (lambda (stx) ...) as a macro which you bind to
> "symbol-syntax?".
>
> Now the expression "(symbol-syntax? blah)" will not be evaluated in the
> regular fashion, because Guile sees that "symbol-syntax?" is registered
> as a macro.
>
> Instead of trying to get the values of "symbol-syntax?" and "blah" like
> it happened with "(symbol? x)", this time Guile calls the procedure
> registered with "symbol-syntax?" immediately, and passes it a "syntax
> object" that represents the whole expression "(symbol-syntax? blah)".
> (Not just the "blah" argument but the whole expression, don't ask why.)
>
>   (syntax-case stx ()
>     ((_ x)
>      ...
>
> Within the procedure, we use "syntax-case" to do pattern-matching on the
> expression "(symbol-syntax? blah)" that is stored in the variable "stx".
>
> We know that the first thing in the expression is "symbol-syntax?"
> because otherwise we wouldn't have been invoked in the first place, so
> we want to ignore that, hence we use the pattern "(_ x)" which ignores
> the first thing (via the underscore) and binds the second thing to "x".
> That second thing is "blah" so "x" contains that now.
>
>   (if (symbol? (syntax->datum #'x))
>       ...
>
> Now "x" contains the element "blah" but to your probable surprise, it's
> not a symbol but rather a syntax object.  Thankfully we can just call
> "syntax->datum" to get the corresponding data value, which is going to
> be the symbol "blah".
>
> You're probably wondering why we wrote #'x instead of just x in our call
> to "syntax->datum" and to be honest I'm not 100% clear on the reason to
> this day, but it's how syntax-case expects you to use pattern variables.
>  You're never allowed to reference them "bare".
>
>     #'(display "yep\n")
>
> Finally, we use #' to create a whole new syntax object, containing the
> expression (display "yep\n").  That syntax object is the value returned
> from our procedure, so Guile puts it where "(symbol-syntax? blah)" was.
>
> When you compile the code, all that actually ends up in the program is
> "(display ...)" with no trace of the original "(symbol-syntax? ...)"
> expression being left.  That's what macros do; they replace code at
> compile time and leave no trace of themselves.
>
> In the second call, "(symbol-syntax? (blah))", the pattern variable "x"
> ends up containing a syntax object representing "(blah)", and calling
> "syntax->datum" on that yields a list and not a symbol, hence we end up
> returning '(display "nope\n")' from the macro.
>
> ----------
>
> All that might be daunting at first but after a while it becomes
> natural, and the power it gives the programmer is really like nothing
> else. :-)
>
> What you intend to do, which is traverse through a whole lambda body and
> find instances of "(f 42)" to replace them, might be a bit tricky.
> Let's say you've written a macro "my-define" which does that, then
> consider the following definition:
>
>   (my-define (foo x)
>     (let ((f 42))
>       (+ f x)))
>
> Now you probably don't want to turn that "(f 42)" into anything else,
> because it's not really a call to your "f".
>
> I've never written a macro yet which does something like that, so I'm
> not sure I can help, but I'm happy to respond to questions about the
> general workings of the macro system.
>
>
> - Taylan
>


-- 
cassette tapes - analog TV - film cameras - you


reply via email to

[Prev in Thread] Current Thread [Next in Thread]