all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Toby Cubitt <tsc25@cantab.net>
To: help-gnu-emacs@gnu.org
Subject: Re: Writing a function/macro in Elisp that generates a function at runtime
Date: Tue, 28 Oct 2008 11:38:20 +0100	[thread overview]
Message-ID: <4906EB9C.10501@dr-qubit.org> (raw)
In-Reply-To: <barmar-0CFC01.01561028102008@mara100-84.onlink.net>


Barry Margolin wrote:
> In article <mailman.2216.1225168079.25473.help-gnu-emacs@gnu.org>,
>  Toby Cubitt <tsc25@cantab.net> wrote:
>> I'm trying to write a function in Elisp that generates a function at
>> runtime, but hitting the limits of my Lisp abilities. Here's a first
>> attempt at the kind of thing I'm trying to do:
>>
>> (defun wrap-insert-function (insfun)
>>   `(lambda (new-data old-cell)
>>      (setf (cell-data old-cell)
>>            (funcall ,insfun new-data (cell-data old-cell)))
>>      old-cell))
[snip]
>> The problem is, because it's quoted, the `setf' macro never gets
>> expanded by the byte-compiler. And that's no good, because the cl
>> package where `setf' is defined shouldn't be loaded at runtime, and
> 
> To do that you'd need lexical closures, but Elisp doesn't have them.  
> Since you're not generating the function until runtime, there's nothing 
> to compile at compile time.

I can start to see how to do it with lexical closures. (How many times
have I wished for them in Elisp! Bring on the lexbind branch...). But is
there really no way to do this without closures? That seems strange. The
above definition works fine, except for the setf issue. As you say, the
run-time generated function obviously can't be compiled, because it
doesn't exist at compile-time. But that's not what I asked for. I want
the setf macro to be *expanded* at compile time into the setf method for
`cell-data', and there *is* enough information at compile-time for that.

I had another go, and came up with the following attempt (I can hear the
Elisp experts whincing already - I know it's ugly!)

(defmacro wrap-insfun-2 (f-2)
  (let ((comma-f `(nil ,f-2)))
    (setcar comma-f ',)
    (macroexpand-all
     `(lambda (new old)
	(setf (cell-data old)
	      (,comma-f (cell-data new)
			(cell-data old)))))))

(defmacro wrap-insfun-1 (f-1)
  `(eval (backquote ,(macroexpand-all `(wrap-insfun-2 ,f-1)))))

(defun wrap-insfun (insfun)
  (wrap-insfun-1 insfun))

This works as long as `wrap-insfun-1' is not byte-compiled (I don't
completely understand why it fails when byte-compiled, but I guess it's
because `backquote' does't work on the byte-compiled expansion of
`wrap-insfun-2'.)

I was trying to have macros generate the body of the wrap-insfun
function, so that I could force setf to be macro-expanded when compiled.
 Getting macros to generate code containing a backquote construct seems
to be tricky, I guess because backquote expansion gets confused by the
commas that are supposed to be part of the generated code, hence hiding
this inside `comma-f'.

Is generating a backquote construct possible using macros, in a robust
way that byte-compiles properly, and without the ugly hack of making use
of Emacs's internal old-style backquote implementation as I've done? Or
is this simply impossible? Or is Elisp lacking some Lisp feature that
would allow this? (reader macros?)


> You don't need to generate a function on the fly for this.  Do something 
> like this:
> 
> (defun insert-with-function (insfun new-data old-cell)
>   (setf (cell-data old-cell)
>         (funcall insfun new-data (cell-data old-cell)))
>   old-cell)

Hmmmm...the simplest ideas are always best. This does sound like a
better approach. Thanks!

I'm still curious about the above macro shenanigans though, since it's
pushing at the boundaries of my understanding of Lisp and I'd like to
understand these issues more fully.

Toby




  reply	other threads:[~2008-10-28 10:38 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <mailman.2216.1225168079.25473.help-gnu-emacs@gnu.org>
2008-10-28  5:56 ` Writing a function/macro in Elisp that generates a function at runtime Barry Margolin
2008-10-28 10:38   ` Toby Cubitt [this message]
2008-10-28 12:42     ` Toby Cubitt
     [not found]     ` <mailman.2265.1225201433.25473.help-gnu-emacs@gnu.org>
2008-10-28 16:47       ` Ted Zlatanov
2008-10-28 17:10         ` Toby Cubitt
2008-10-27 13:30 Toby Cubitt
2008-10-28 18:09 ` Johan Bockgård
2008-10-28 17:21   ` Toby Cubitt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4906EB9C.10501@dr-qubit.org \
    --to=tsc25@cantab.net \
    --cc=help-gnu-emacs@gnu.org \
    --cc=toby-dated-1225625904.c16578@dr-qubit.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.