From: Dave
Subject: emulate (loop for..)
Date: 
Message-ID: <4kx0b.251910$Ny5.7729086@twister2.libero.it>
(defun for (start stop step fnc)
   (do ((ix start (+ ix step)))
      ((>= ix stop) ix)
         (print ix)))

> (for 0 6 2 nil)
0
2
4
6

(defun for (start stop step fnc)
   (do ((ix start (+ ix step)))
      ((>= ix stop) ix)
         (eval fnc)))

>(for 0 8 2 '(print ix))
error: unbound variable - ix

Why??
I use Xlisp and it don't have the "(loop for..)".
Could anybody help me?
Thank You very much

Dave

From: Chris Perkins
Subject: Re: emulate (loop for..)
Date: 
Message-ID: <6cb6c81f.0308191731.55c5e61d@posting.google.com>
"Dave" <·········@iol.it> wrote in message news:<························@twister2.libero.it>...

[snip]

> (defun for (start stop step fnc)
>    (do ((ix start (+ ix step)))
>       ((>= ix stop) ix)
>          (eval fnc)))
> 
> >(for 0 8 2 '(print ix))
> error: unbound variable - ix
> 
> Why??
> I use Xlisp and it don't have the "(loop for..)".
> Could anybody help me?
> Thank You very much
> 
> Dave

I'm terrible at explaining these things, but here goes:   There are
two "evaluations" occuring.  Once at your prompt, and once at your
(eval... statement.  At the prompt the argument '(print ix) is
evaluated to (print ix).   At this time it is not yet executed, but
it's value is discovered to be a list with the function print in the
first entry, and some unbound symbol ix in the second (because, at
that first prompt, ix is not yet defined). So, at the prompt, your
expression is evaluated to the command "print some unbound symbol". 
When this is finally passed down to the call to (eval...   Lisp does
not attempt to re-investigate that unbound symbol.  Instead it
evaluates "print some unbound symbol".  Thus your error.

A possible solution:  double quote it.   ''(print ix)


You want to be careful using eval, though.  In most implementation it
is slow and operates outside of any lexical context. In xLisp, though,
you can optionally pass in a third argument which is the environment
in which to evaluate the expression, so that might help matters.  But
I use eval rarely, and never in xLisp, so what do I know?

Hope this helps, and, moreover, that my explanation isn't wildly wrong
or undecipherable.

Chris Perkins
Media Lab, Inc.

P.S. Upon re-reading it might be thought that I'm suggesting that
there is a difference between execution and evaluation, but that's not
what I mean. I just mean it hasn't been evaluated a second time (yet).
From: Dave
Subject: Re: emulate (loop for..)
Date: 
Message-ID: <FoG0b.252312$Ny5.7746345@twister2.libero.it>
"Chris Perkins" <········@medialab.com> wrote:

> I'm terrible at explaining these things, but here goes:   There are
> two "evaluations" occuring.  Once at your prompt, and once at your
> (eval... statement.  At the prompt the argument '(print ix) is
> evaluated to (print ix).   At this time it is not yet executed, but
> it's value is discovered to be a list with the function print in the
> first entry, and some unbound symbol ix in the second (because, at
> that first prompt, ix is not yet defined). So, at the prompt, your
> expression is evaluated to the command "print some unbound symbol". 
> When this is finally passed down to the call to (eval...   Lisp does
> not attempt to re-investigate that unbound symbol.  Instead it
> evaluates "print some unbound symbol".  Thus your error.
> 
> A possible solution:  double quote it.   ''(print ix)
> 

I have tried but it does not seems to work very well. 

Xlisp>(for 0 8 2 ''(print ix))
XLisp>8

I'm using Xlisp-plus 3.04 with Common Lisp extensions, by Tom Almy.

Thanks you for all explanations.
Dave
From: Matthew Danish
Subject: Re: emulate (loop for..)
Date: 
Message-ID: <20030820204834.GD1454@mapcar.org>
On Tue, Aug 19, 2003 at 06:31:48PM -0700, Chris Perkins wrote:
> Hope this helps, and, moreover, that my explanation isn't wildly wrong

It is, I'm afraid to say.

-- 
; Matthew Danish <·······@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."
From: Matthew Danish
Subject: Re: emulate (loop for..)
Date: 
Message-ID: <20030819230845.GB1454@mapcar.org>
On Tue, Aug 19, 2003 at 10:15:28PM +0000, Dave wrote:
> (defun for (start stop step fnc)
>    (do ((ix start (+ ix step)))
>       ((>= ix stop) ix)
>          (eval fnc)))
> 
> >(for 0 8 2 '(print ix))
> error: unbound variable - ix

Naturally: using EVAL evaluates the code in a null lexical environment.
IX is a lexical variable.

What you REALLY want to do is this:

(defun %for (start stop step fnc)
  (do ((ix start (+ ix step)))
      ((>= ix stop) ix)
    (funcall fnc ix)))

(%for 0 8 2 (lambda (i) (print i)))

and then

(defmacro for ((var start stop &optional (step 1)) &body body)
  `(%for ,start ,stop ,step (lambda (,var) ,@body)))

(for (i 0 8 2) (print i))

-- 
; Matthew Danish <·······@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."
From: Dave
Subject: Re: emulate (loop for..)
Date: 
Message-ID: <jjG0b.252702$lK4.7811719@twister1.libero.it>
"Matthew Danish" <·······@andrew.cmu.edu> wrote:

> What you REALLY want to do is this:
>
> (defun %for (start stop step fnc)
>   (do ((ix start (+ ix step)))
>       ((>= ix stop) ix)
>     (funcall fnc ix)))
>
> (%for 0 8 2 (lambda (i) (print i)))

It works.

>
> (defmacro for ((var start stop &optional (step 1)) &body body)
>   `(%for ,start ,stop ,step (lambda (,var) ,@body)))

XLISP> error: bad formal argument list

Thanks you.
Dave
From: Matthew Danish
Subject: Re: emulate (loop for..)
Date: 
Message-ID: <20030820205035.GE1454@mapcar.org>
On Wed, Aug 20, 2003 at 08:29:03AM +0000, Dave wrote:
> "Matthew Danish" <·······@andrew.cmu.edu> wrote:
> > (defmacro for ((var start stop &optional (step 1)) &body body)
> >   `(%for ,start ,stop ,step (lambda (,var) ,@body)))
> XLISP> error: bad formal argument list

As Chris pointed out, XLISP does not have as good a macro facility as
Common Lisp.  I wrote the code in CL, since I don't know XLISP.  I
assume you can adapt it to your own purposes.

-- 
; Matthew Danish <·······@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."
From: Nick Levine
Subject: Re: emulate (loop for..)
Date: 
Message-ID: <8732fc48.0308192029.78618a9c@posting.google.com>
> (defun for (start stop step fnc)
>    (do ((ix start (+ ix step)))
>       ((>= ix stop) ix)
>          (eval fnc)))
> 
> >(for 0 8 2 '(print ix))
> error: unbound variable - ix
> 
> Why??
> I use Xlisp and it don't have the "(loop for..)".

The mistake you made is to assume that the lexical variable ix in your
function definition is the same as the (assumed dynamic) variable
named by the symbol ix in the argument '(print ix). See section
3.1.2.1.1 "Symbols as Forms" in the hyperspec, or read any decent book
on lisp.

It's difficult to tell from this example what you actually wanted to
achieve. How general do you want this to be?

CL-USER 3 > (defun for-print (start stop step)
              (do ((ix start (+ ix step)))
                  ((>= ix stop) ix)
                (print ix)))
FOR-PRINT

CL-USER 4 > (for-print 0 8 2)

0 
2 
4 
6 
8

CL-USER 5 > (defun for-funcall (start stop step fnc)
              (do ((ix start (+ ix step)))
                  ((>= ix stop) ix)
                (funcall fnc ix)))
FOR-FUNCALL

CL-USER 6 > (for-funcall 0 8 2 'print)

0 
2 
4 
6 
8

CL-USER 7 > (defmacro for-ugly (start stop step fnc)
              `(do ((ix ,start (+ ix ,step)))
                   ((>= ix ,stop) ix)
                 ,fnc))
FOR-UGLY

CL-USER 8 > (for-ugly 0 8 2 (print ix))

0 
2 
4 
6 
8

CL-USER 9 > (defmacro for-better ((var start stop &optional (step 1))
&body body)
              `(do ((,var ,start (+ ,var ,step)))
                   ((>= ,var ,stop) ,var)
                 ,@body))
FOR-BETTER

CL-USER 10 > (for-better (ix 0 8 2)
                         (print ix))

0 
2 
4 
6 
8

CL-USER 11 >
From: Dave
Subject: Re: emulate (loop for..)
Date: 
Message-ID: <EoG0b.252310$Ny5.7746288@twister2.libero.it>
"Nick Levine" <···@ravenbrook.com> wrote:
 
> CL-USER 5 > (defun for-funcall (start stop step fnc)
>               (do ((ix start (+ ix step)))
>                   ((>= ix stop) ix)
>                 (funcall fnc ix)))
> FOR-FUNCALL
> 
> CL-USER 6 > (for-funcall 0 8 2 'print)
>

It works with XLisp but I need to evaluate a whole expression.

>
> CL-USER 7 > (defmacro for-ugly (start stop step fnc)
>               `(do ((ix ,start (+ ix ,step)))
>                    ((>= ix ,stop) ix)
>                  ,fnc))
> FOR-UGLY
> 
> CL-USER 8 > (for-ugly 0 8 2 (print ix))

It works.

> 
> CL-USER 9 > (defmacro for-better ((var start stop &optional (step 1))
> &body body)
>               `(do ((,var ,start (+ ,var ,step)))
>                    ((>= ,var ,stop) ,var)
>                  ,@body))


Xlisp> error: bad formal argument list 


Thanks you for explanations.
Dave
From: Alexey Dejneka
Subject: Re: emulate (loop for..)
Date: 
Message-ID: <9eea6ac3.0308192029.5c816d8b@posting.google.com>
"Dave" <·········@iol.it> wrote in message news:<························@twister2.libero.it>...
> (defun for (start stop step fnc)
>    (do ((ix start (+ ix step)))
>       ((>= ix stop) ix)
>          (eval fnc)))
> 
> >(for 0 8 2 '(print ix))
> error: unbound variable - ix
> 
> Why??

IX is a lexical variable, visible only textually inside the form it is
defined in. You can do two things: either pass a function to FOR:

  (defun for (start stop step fnc) 
     (do ((ix start (+ ix step))) 
         ((>= ix stop) ix) 
       (funcall fnc ix)))

  (for 0 8 2 #'(lambda (i) (print i)))

or make FOR a macro:

  (defmacro for (start stop step body-form)
    (let ((start-var (gensym))
          (stop-var (gensym))
          (step-var (gensym)))
      `(let ((,start-var ,start)
             (,stop-var ,stop)
             (,step-var ,step))
         (do ((ix ,start-var (+ ix ,step-var))) 
             ((>= ix ,stop-var) ix) 
           ,body-form))))

  (for 0 8 2 (print ix))

or better:

  (defmacro for (var start stop step body-form)
    (let ((start-var (gensym))
          (stop-var (gensym))
          (step-var (gensym)))
      `(let ((,start-var ,start)
             (,stop-var ,stop)
             (,step-var ,step))
         (do ((,var ,start-var (+ ,var ,step-var))) 
             ((>= ,var ,stop-var) ,var) 
           ,body-form))))

  (for i 0 8 2 (print i))

You might be interested in this tutorial:

http://www.psg.com/~dlamkins/sl/contents.html

-- 
Regards,
Alexey Dejneka
From: Dave
Subject: Re: emulate (loop for..)
Date: 
Message-ID: <ijG0b.252700$lK4.7812049@twister1.libero.it>
"Alexey Dejneka" <········@comail.ru> wrote:

>   (defun for (start stop step fnc) 
>      (do ((ix start (+ ix step))) 
>          ((>= ix stop) ix) 
>        (funcall fnc ix)))
> 
>   (for 0 8 2 #'(lambda (i) (print i)))

It seems to work.. ;-)

> 
> or make FOR a macro:
> 
>   (defmacro for (start stop step body-form)
>     (let ((start-var (gensym))
>           (stop-var (gensym))
>           (step-var (gensym)))
>       `(let ((,start-var ,start)
>              (,stop-var ,stop)
>              (,step-var ,step))
>          (do ((ix ,start-var (+ ix ,step-var))) 
>              ((>= ix ,stop-var) ix) 
>            ,body-form))))
> 
>   (for 0 8 2 (print ix))

It works fine with Xlisp.

> or better:
> 
>   (defmacro for (var start stop step body-form)
>     (let ((start-var (gensym))
>           (stop-var (gensym))
>           (step-var (gensym)))
>       `(let ((,start-var ,start)
>              (,stop-var ,stop)
>              (,step-var ,step))
>          (do ((,var ,start-var (+ ,var ,step-var))) 
>              ((>= ,var ,stop-var) ,var) 
>            ,body-form))))
> 
>   (for i 0 8 2 (print i))

it works better! :-)

> You might be interested in this tutorial:
> 
> http://www.psg.com/~dlamkins/sl/contents.html
> 

Thanks You very much.
Dave
From: Chris Perkins
Subject: Re: emulate (loop for..)
Date: 
Message-ID: <6cb6c81f.0308192130.57357ccf@posting.google.com>
Matthew Danish's reply was a good one, but unfortunately xLisp isn't
CommonLisp enough to support it. defmacro doesn't support
destructuring bind, there's no funcall...

Dave, are you using xLisp 3.0?  Have you looked at the macros.lsp file
that comes with it?  It has great examples of do, dotimes, dolist, and
other macros that loop and perform the powerful trick of intentional
variable capture.

Here is a version of for xLisp that will do what you want:

;; WARNING: this is not Common Lisp, but xLisp which is more like
Scheme.
;; Usage: (for (var start stop step [result]) BODY)
;; Example: (for (ix 0 8 2 (format #t "exited loop because ~A" ix))
(print ix))
(define-macro (for range &body body)
  (let ((counterVar (car range))
        (startVar (cadr range))
	(stopVar (caddr range))
	(stepVar (cadddr range))
	(result  (car (cddddr range)))
        (loop (gensym)))
    `(let ,loop ((,counterVar ,startVar))
       (if (<= ,counterVar ,stopVar)
         (begin
           ,@body
           (,loop (+ ,counterVar 1)))
	 ,result))))

Besides letting you pass in start, stop, and step, it is set up so
that the user of the (for macro can pass in the name of the variable
that they want to be used for the counter.  This way, both the return
and body expressions can refer to that variable.   The user of the
(for macro doesn't have to know anything about an internal variable
named "ix" - because the user provides that variable name for the
macro.


Hope this helps,

Chris Perkins
Media Lab, Inc.
From: Dave
Subject: Re: emulate (loop for..)
Date: 
Message-ID: <jjG0b.252701$lK4.7811813@twister1.libero.it>
"Chris Perkins" <········@medialab.com> wrote:

> Matthew Danish's reply was a good one, but unfortunately xLisp isn't
> CommonLisp enough to support it. defmacro doesn't support
> destructuring bind, there's no funcall...
>
> Dave, are you using xLisp 3.0?  Have you looked at the macros.lsp file
> that comes with it?  It has great examples of do, dotimes, dolist, and
> other macros that loop and perform the powerful trick of intentional
> variable capture.
>
>...[cut]...
>

I'm using Xlisp-plus 3.04 with Common Lisp extensions, by Tom Almy.
I had forgotten to say that I would have need of a method that functions
well with XLISP and CLISP.

Many of your examples have worked very well.

Thanks all!!

Dave
From: Pascal Costanza
Subject: Re: emulate (loop for..)
Date: 
Message-ID: <costanza-6F50EE.01125320082003@news.netcologne.de>
In article <························@twister2.libero.it>,
 "Dave" <·········@iol.it> wrote:

> (defun for (start stop step fnc)
>    (do ((ix start (+ ix step)))
>       ((>= ix stop) ix)
>          (print ix)))
> 
> > (for 0 6 2 nil)
> 0
> 2
> 4
> 6
> 
> (defun for (start stop step fnc)
>    (do ((ix start (+ ix step)))
>       ((>= ix stop) ix)
>          (eval fnc)))
> 
> >(for 0 8 2 '(print ix))
> error: unbound variable - ix
> 
> Why??
> I use Xlisp and it don't have the "(loop for..)".
> Could anybody help me?
> Thank You very much

I don't know much about Xlisp but since I have heard it is similar to 
Common Lisp, here are some guesses:

+ CL's eval is executed in the current dynamic environment and the null 
lexical environment. Because fnc is lexically bound, eval doesn't see 
its binding. You could try to bind fnc to a dynamic/special variable and 
use eval with that variable.

+ Another option in CL would be to use progv for that case. At least I 
can imagine that it could be used for that purpose. On the other hand, I 
don't have enough knowledge about the actually intended use of progv. 
Maybe some CL experts on this list can tell us more.

So, maybe Xlisp also has progv.

+ Then again, why don't you make fnc a real lambda expression, as 
follows?

(defun for (start stop step fnc)
  (do ((ix start (+ ix step)))
     ((>= ix stop) ix)
        (funcall fnc ix)))

(for 0 8 2 (lambda (ix) (print ix)))

Again, this is CL.

If you think that the lambda expression is a bit too verbose, a macro 
could help:

(defmacro for (start stop step &body body)
  `(do ((ix ,start (+ ix ,step)))
      ((>= ix ,stop) ix)
         ,@body))

(for 0 8 2
  (print ix))

However, note two things:

+ The macro above is a rough sketch. I haven't tested it, and especially 
step and stop are not evaluated in the correct order (from left to 
right).

+ It seems a little questionable to make the symbol ix visible in the 
body. I think it would be better to let the user of the macro choose an 
explicit name, like this: (for ix 0 8 2 ...)


I don't know if these remarks are of any help to you, but I hope so. ;)


Pascal
From: Dave
Subject: Re: emulate (loop for..)
Date: 
Message-ID: <EoG0b.252311$Ny5.7746496@twister2.libero.it>
"Pascal Costanza" <········@web.de> wrote:

> + Then again, why don't you make fnc a real lambda expression, as
> follows?
>
> (defun for (start stop step fnc)
>   (do ((ix start (+ ix step)))
>      ((>= ix stop) ix)
>         (funcall fnc ix)))
>
> (for 0 8 2 (lambda (ix) (print ix)))

It works fine.

> If you think that the lambda expression is a bit too verbose, a macro
> could help:
>
> (defmacro for (start stop step &body body)
>   `(do ((ix ,start (+ ix ,step)))
>       ((>= ix ,stop) ix)
>          ,@body))
>
> (for 0 8 2
>   (print ix))
>

I have tried but it does not seems to work..
XLisp> error: too few arguments

Thanks you for all explanations.
Dave