all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Oliver Scholz <alkibiades@gmx.de>
Subject: tail recursion hack in Emacs Lisp?
Date: Fri, 16 Jul 2004 17:07:19 +0200	[thread overview]
Message-ID: <u7jt46leg.fsf@ID-87814.user.uni-berlin.de> (raw)

I like tail recursion a lot, because I regard it as a means to specify
the flow of control that is IMO the right way for /some/ problems.
Thus tail call reduction is on the top of my personal wish list for
enhancements of Emacs Lisp---even before closures and greater speed.

I have been wondering for a while, whether it would be possible to
fake tail recursion without hacking the byte code compiler.  Say, if
we have an `iterate' macro like in CMU CL (which in turn is inspired
by Scheme's named let): would it be possible that the macroexpanded
code would be non-recursive Emacs Lisp code?

Today I got bored in my lunch break and came up with this.

(iterate fact ((n n)
	       (r 1))
  (if (= n 1)
      r
    (fact (1- n) (* n r))))

should expand to:

(let ((continue t)
      (result (list n 1)))
  (while continue
    (setq result
	  (catch 'repeat
	    (setq result
		  (apply
		   (lambda (n r)
		     (if (= n 1)
			 r
		       (throw 'repeat (list (1- n) (* n r)))))
		   result))
	    (setq continue nil)
	    result)))
  result)


(Of course, a code walker would be necessary.) I can't see any
problems with that approach right know. But lacking experience in
implementing Lisp, I might be missing something.

So my question is: Can anybody think of a case where this approach
would break?

While I am at it: I quickly hacked something together:

(defmacro iterate (name arglist &rest body)
  (let ((catch-symbol (make-symbol "--repeat"))
	(continue (make-symbol "--continue"))
	(result (make-symbol "--result"))
	(lambda-list (mapcar 'car arglist))
	(initial-args (mapcar 'cadr arglist)))
    (setq body (iterate-code-walk body name catch-symbol))
    `(let ((,continue t)
	   (,result (list ,@initial-args)))
       (while ,continue
	 (setq ,result
	       (catch ',catch-symbol
		 (setq ,result
		       (apply
			(lambda ,lambda-list
			  ,@body)
			,result))
		 (setq ,continue nil)
		 ,result)))
       ,result)))

(defun iterate-code-walk (exp sym catch-sym)
  (cond ((and (listp exp)
	      (eq (car exp) 'quote))
	 exp)
	((and (listp exp)
	      (eq (car exp) sym))
	 (list 'throw `(quote ,catch-sym)
	       (cons 'list (cdr exp))))
	((listp exp)
	 (iterate-code-walk-list exp sym catch-sym))
	(t exp)))

(defun iterate-code-walk-list (exp sym catch-sym)
  (mapcar (lambda (el)
	    (iterate-code-walk el sym catch-sym))
	  exp))       


    Oliver
-- 
29 Messidor an 212 de la Révolution
Liberté, Egalité, Fraternité!

             reply	other threads:[~2004-07-16 15:07 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-07-16 15:07 Oliver Scholz [this message]
2004-07-16 16:23 ` tail recursion hack in Emacs Lisp? Oliver Scholz
2004-07-16 16:42   ` Oliver Scholz
2004-07-16 16:53   ` Stefan Monnier
2004-07-16 17:37     ` Oliver Scholz

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=u7jt46leg.fsf@ID-87814.user.uni-berlin.de \
    --to=alkibiades@gmx.de \
    /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.