all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* question on elisp best practive
@ 2007-10-09 18:07 Aemon
  2007-10-10  6:22 ` Barry Margolin
  0 siblings, 1 reply; 3+ messages in thread
From: Aemon @ 2007-10-09 18:07 UTC (permalink / raw)
  To: help-gnu-emacs

Hi all,

I've got a lot of code that traverses trees and does something at
every node. I'd like to abstract the traversal part of the code, and
just pass in the bit that does the action. Something like:

(defun visit-each (tree func depth)
  (funcall func tree depth)
  (dolist (ea (tree-children tree))
    (visit-each ea (+ 1 depth))))


This seems to work pretty well, called like so:

(visit-each my-tree
	    (lambda (subtree depth)
	      (message "%s %s" subtree depth)))


However, as it's not a closure I'm passing in, I would get into
trouble if I tried:

(visit-each my-tree
	    (let ((depth "my depth"))
	      (lambda (subtree)
		(message "%s %s" subtree depth))))

Elisp's dynamic scope would cause my local binding of 'depth' -> "my
depth" to always be shadowed.

Which sucks, because there is often extra information that I need to
pass into the lambda somehow, but I can't reliably reference it
without being aware of which variable names the traversal function is
binding.

So now I'm thinking the best thing is to do the traversal iteratively,
inline, in a macro, and take special care to gensym all of my macro
variables.

Something like:


(defmacro visit-each (tree depth each-tree-form &rest body)
  (let ((tree-form (gensym))
	(stack-form (gensym))
	(tmp-child-form (gensym)))
	`(let* ((,tree-form ,tree)
		(,stack-form (list ,tree-form)))
	   (while (not (null ,stack-form))
	     (let ((,each-tree-form (pop ,stack-form)))
	       ,@body)
	     (dolist (,tmp-child-form (children-of ,tree-form))
	       (push ,tmp-child-form ,stack-form))))))


Is there a better way to do this?

Thanks!

Aemon

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: question on elisp best practive
  2007-10-09 18:07 question on elisp best practive Aemon
@ 2007-10-10  6:22 ` Barry Margolin
  2007-10-12  0:51   ` Aemon
  0 siblings, 1 reply; 3+ messages in thread
From: Barry Margolin @ 2007-10-10  6:22 UTC (permalink / raw)
  To: help-gnu-emacs

In article <1191953276.499830.12710@22g2000hsm.googlegroups.com>,
 Aemon <aemoncannon@gmail.com> wrote:

> Hi all,
> 
> I've got a lot of code that traverses trees and does something at
> every node. I'd like to abstract the traversal part of the code, and
> just pass in the bit that does the action. Something like:
> 
> (defun visit-each (tree func depth)
>   (funcall func tree depth)
>   (dolist (ea (tree-children tree))
>     (visit-each ea (+ 1 depth))))
> 
> 
> This seems to work pretty well, called like so:
> 
> (visit-each my-tree
> 	    (lambda (subtree depth)
> 	      (message "%s %s" subtree depth)))
> 
> 
> However, as it's not a closure I'm passing in, I would get into
> trouble if I tried:
> 
> (visit-each my-tree
> 	    (let ((depth "my depth"))
> 	      (lambda (subtree)
> 		(message "%s %s" subtree depth))))
> 
> Elisp's dynamic scope would cause my local binding of 'depth' -> "my
> depth" to always be shadowed.

Does it work if you use lexical-let instead of let?

-- 
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: question on elisp best practive
  2007-10-10  6:22 ` Barry Margolin
@ 2007-10-12  0:51   ` Aemon
  0 siblings, 0 replies; 3+ messages in thread
From: Aemon @ 2007-10-12  0:51 UTC (permalink / raw)
  To: help-gnu-emacs

On Oct 10, 2:22 am, Barry Margolin <bar...@alum.mit.edu> wrote:
> In article <1191953276.499830.12...@22g2000hsm.googlegroups.com>,
>
>
>
>  Aemon <aemoncan...@gmail.com> wrote:
> > Hi all,
>
> > I've got a lot of code that traverses trees and does something at
> > every node. I'd like to abstract the traversal part of the code, and
> > just pass in the bit that does the action. Something like:
>
> > (defun visit-each (tree func depth)
> >   (funcall func tree depth)
> >   (dolist (ea (tree-children tree))
> >     (visit-each ea (+ 1 depth))))
>
> > This seems to work pretty well, called like so:
>
> > (visit-each my-tree
> >        (lambda (subtree depth)
> >          (message "%s %s" subtree depth)))
>
> > However, as it's not a closure I'm passing in, I would get into
> > trouble if I tried:
>
> > (visit-each my-tree
> >        (let ((depth "my depth"))
> >          (lambda (subtree)
> >            (message "%s %s" subtree depth))))
>
> > Elisp's dynamic scope would cause my local binding of 'depth' -> "my
> > depth" to always be shadowed.
>
> Does it work if you use lexical-let instead of let?
>
> --
> Barry Margolin, bar...@alum.mit.edu
> Arlington, MA
> *** PLEASE post questions in newsgroups, not directly to me ***
> *** PLEASE don't copy me on replies, I'll read them in the group ***

Wow - I was not aware of that :)
That seems to work pretty well. I guess it's probably well understood
that lambdas passed to library functions should lexical-let ( or be
careful what variables they reference) ?

Thanks!
Aemon

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2007-10-12  0:51 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-10-09 18:07 question on elisp best practive Aemon
2007-10-10  6:22 ` Barry Margolin
2007-10-12  0:51   ` Aemon

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.