From: Mirko Luedde
Subject: Elisp newbie: changing function problem
Date: 
Message-ID: <39153F85.BD546D2E@Computer.Org>
Hi folks! 

I'm trying to construct a recursive arithmetic via Emacs Lisp
(requiring the cl package) and am facing the problem that a function
seems to change the first time I apply it.

First I let (for definitions see postscriptum) 

<- (setq f2 (mil-juxtapose (list (mil-project 1) (mil-project 2))))
-> ; ... left out

This should be a function projecting a list of integers onto 
the first two components. 
But when I apply the function two times I obtain

<- (funcall f2 (list 1 2 3))
-> (1 2) ; ok
<- (funcall f2 (list 1 2 3))
-> nil ; why that? is stable from now.

Does anybody have any hint? 

Thanks, Mirko. 

P.S. The definitions: 

(defun mil-project (n)
  "Return a function that projects a list of integers onto the n-th
element from the list (counting from 1) and returns it as a 1-element
list."

  (lexical-let ((n n))
    ;; linear search here. perhaps better use Lisp vectors instead of
    ;; Lisp lists?
    (lambda (x) (list (nth (1- n) x)))))

(defun mil-juxtapose (f) 
  "Return the juxtaposition of the functions from the list f as a new
function.

The result function g is defined as g(x) = (f1(x),..,fn(x)).

Example:\n <- (funcall (mil-juxtapose (list 'mil-plus-1 'mil-plus-1))
(list
0))\n -> (1 1)"

  (lexical-let ((f f))
    (lambda (x)
      (let ((y nil))
	(while (consp f) 
	  ;; apply the first function from the function list and
	  ;; append the result to the outgoing list.
	  (setq y (nconc y (funcall (car f) x)))
	  ;; next function from list
	  (setq f (cdr f)))
	y))))
-- 
Mirko Luedde (············@Computer.Org)
From: Will Mengarini
Subject: Re: Elisp newbie: changing function problem
Date: 
Message-ID: <8f6qpg$fnl$1@eskinews.eskimo.com>
Mirko Luedde <············@Computer.Org> 2000-05-07=Su 12:03:49 +0200:

> [[For clarity, I have completely paraphrased his post & docstring.  --WM]
>
> Using Emacs Lisp with (require 'cl), I am trying to build a function
> that emulates #'compose; I call it #'mil-juxtapose.  Here's the code:
>
> (defun mil-juxtapose (f)
>   "Return the juxtaposition of the functions from the list f as a new
> function.  Example:
> \(funcall (mil-juxtapose (list #'f1 #'f2)) x) => (list (f1 x) (f2 x))"
>   (lexical-let ((f f))
>     (lambda (x)
>       (let ((y nil))
>       (while (consp f)
>         ;; apply the first function from the function list and
>         ;; append the result to the outgoing list.
>         (setq y (nconc y (funcall (car f) x)))
>         ;; next function from list
>         (setq f (cdr f)))
>       y))))
>
> However, when I invoke a function returned by #'mil-juxtapose, I discover
> that the returned function only works correctly the first time; all
> subsequent invocations of it return nil.  Example:
>
>   (setq f-mil (mil-juxtapose (list (lambda (n) (list (1+ n)))
>                                    (lambda (n) (list (+ 2 n))))))
>   (funcall f-mil 4)
>    => (5 6)
>   (funcall f-mil 4)
>    => nil
>   (funcall f-mil 4)
>    => nil
>
> Why does this happen?]

Because (lambda (x) ...) is defined *inside* (lexical-let ((f f)) ...),
and destructively modifies f, looping until (null f).  On all
subsequent invocations, of course, (null f) is initially t,
so nil is immediately returned.  Remember that the #'lexical-let isn't
evaluated every time the returned (lambda (x) ...) is invoked; it's evaluated
*once*, when the returned (lambda (x) ...) is *created*, and that's the only
time at which f (the list of functions) is initialized.

This would work (maintaining your convention that the juxtaposed
functions are required to all return lists):

(defun wm-juxtapose-0 (f)
  (check-type f list)
  (lexical-let ((f f))
    (lambda (x)
      (let ((y '())
            (functions f)
            one-result)
        (while (not (endp functions))
          (setq one-result (funcall (car functions) x))
          (check-type one-result list)
          (callf nconc y one-result)
          (callf cdr functions))
        y))))

(setq f-wm-0 (wm-juxtapose-0 (list (lambda (n) (list (1+ n)))
                                   (lambda (n) (list (+ 2 n))))))

(funcall f-wm-0 4)
 => (5 6)
(funcall f-wm-0 4)
 => (5 6)

#'callf isn't standard in Common Lisp, but a very useful extension
built in to Emacs Lisp cl.el.  C-x C-e: (describe-function #'callf)

#'check-type works the same in Common Lisp as in Emacs Lisp cl.el.
#'endp in ELisp is compatible with Common Lisp, but doesn't provide
the same error checking; in my own ELisp I redefine it as

(defun endp (list)
  "Error unless (listp LIST), else (null LIST).

The purpose of this is to check for the end of a list you're iterating
through when you're not prepared to cope with a dotted list; this will
signal an error when you reach the end of a dotted list, but will
return t when you reach the end of a proper list."
  (check-type list list)
  (null list))

A version of juxtapose using the extended LOOP macro is clearer:

(defun wm-juxtapose-1 (f)
  (check-type f list)
  (lexical-let ((f f))
    (lambda (x)
      (loop for function in f
            as one-result = (funcall function x)
            do (check-type one-result list)
            nconc one-result))))

(setq f-wm-1 (wm-juxtapose-1 (list (lambda (n) (list (1+ n)))
                                   (lambda (n) (list (+ 2 n))))))

(funcall f-wm-1 4)
 => (5 6)
(funcall f-wm-1 4)
 => (5 6)

Here's a different approach that may take a while to puzzle through:

(defun circular-list (&rest args)
  "Create a circular list composed of ARGS.
Note that any attempt to *display* this value, or to do anything else that
attempts to iterate over all its elements, will send Emacs into an endless
loop.  The value can be used in other ways, however; on comp.lang.lisp
  (mapcar #'funcall <list-of-functions> (circular-list some-single-arg))
and
  (apply #'mapcar #'funcall <list-of-functions>
         (mapcar #'circular-list some-list-of-arguments))
were suggested, mutatis mutandi, as ways of invoking multiple functions on a
single set of args."
  (nconc args args))

(defun wm-juxtapose-2 (f)
  (check-type f list)
  (lexical-let ((f f))
    (lambda (x) (mapcan #'funcall f (circular-list x)))))

(funcall f-wm-2 4)
 => (5 6)
(funcall f-wm-2 4)
 => (5 6)

                 Will Mengarini  <······@eskimo.com>
         Free software: the Source will be with you, always.