From: Jon
Subject: Memory-lapse CL question about eval and let
Date: 
Message-ID: <12356n5mj55la8c@corp.supernews.com>
I have a question I was hoping someone who's used Lisp more recently than me
(I'm coming back to it after a long break, and am new to CL) could help
with.

Why does:

    (let (X) (setq x 1) (setq f ('+ x x)) (eval f))

Not work - it says (LispWorks, that is) x is unbound, but it's inside the
let scope?

If anyone's feeling helpful I'd also love to know why (let (x (read)) ...
doesn't work (the read doesn't happen).

Thanks in advance.
Jon

From: Pascal Bourguignon
Subject: Re: Memory-lapse CL question about eval and let
Date: 
Message-ID: <871wwdffok.fsf@thalassa.informatimago.com>
"Jon" <···@nospam.com> writes:

> I have a question I was hoping someone who's used Lisp more recently than me
> (I'm coming back to it after a long break, and am new to CL) could help
> with.
>
> Why does:
>
>     (let (X) (setq x 1) (setq f ('+ x x)) (eval f))
>
> Not work - it says (LispWorks, that is) x is unbound, but it's inside the
> let scope?

First:

(quote +) is not a function.  Therefore ((quote +) x x) is meaningless:


[51]> (let (X) (setq x 1) (setq f ('+ x x)) (eval f))

*** - EVAL: '+ is not a function name; try using a symbol instead


Next, assuming you meant:

     (let (X) (setq x 1) (setq f (quote (+ x x))) (eval f))

the problem is that X is a lexical variable. Inside the LET, there is
a lexical environment where X is bound to 1 (after the setq x).  But
EVAL evaluates the form in the NULL lexical environment, where only
dynamic variables are available.

This is the reason why EVAL is frowned upon in CL in most cases.

Instead, you can provide EVAL a form that establish its own lexical
scope with its lexical variables bound to the values:

    (let (X) 
       (setq x 1)
       (eval `(let ((x ,x)) (+ x x))))

Note that this obviously prevent the form passed to EVAL to modify the
outer binding:

    (let (X) 
       (setq x 1)
       (print (eval `(let ((x ,x)) (setq x (+ 2 x)))))
       x)

prints:  3
returns: 1


> If anyone's feeling helpful I'd also love to know why (let (x (read)) ...
> doesn't work (the read doesn't happen).

Read again the syntax of LET:
http://www.lispworks.com/documentation/HyperSpec/Body/s_let_l.htm

  (let (x (read)) ...)

binds a variable named X to NIL and a variable named READ to NIL.

  (let (a
        b
        c
        x
        (d)
        (e)
        (read)
        (f 1)
        (g 2)
        (write 3))
    (list a b c x d e read f g write))

--> (NIL NIL NIL NIL NIL NIL NIL 1 2 3)

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

THIS IS A 100% MATTER PRODUCT: In the unlikely event that this
merchandise should contact antimatter in any form, a catastrophic
explosion will result.
From: Jon
Subject: Re: Memory-lapse CL question about eval and let
Date: 
Message-ID: <eKmdnXAo4fXYVK_ZRVnyig@pipex.net>
Okay, I really wrote that too quickly (but there was a big traffic jam
outside and I wanted to get out before everything stopped).

Yes, I did mean '(+ x x), I just typed too quickly...

Thanks for realising what I meant and explaining the eval scope issue - I do
wonder how would you write it then (less messily than the extra let, if
that's possible)?

Also the let thing suffered from a lack of brackets, sorry 'bout that, but
they'd completely coned off the road I would normally drive down and I was
distracted. I was really asking if you could initialise to (read) in a let
(or presumably let* if you want more than one) as it didn't work for me.
(Like the previous one my actual test case was better written.)

What's wrong with anti-matter anyway, very handy for problem removing, just
add to road cones and shorten journey times... well, except for the falling
down the big hole bit...
Cheers
Jon
From: Raffael Cavallaro
Subject: Re: Memory-lapse CL question about eval and let
Date: 
Message-ID: <2006040418200316807-raffaelcavallaro@pasdespamsilvousplaitmaccom>
On 2006-04-04 15:30:16 -0400, "Jon" <···@nospam.com> said:

> Thanks for realising what I meant and explaining the eval scope issue - I do
> wonder how would you write it then (less messily than the extra let, if
> that's possible)?

You could avoid using eval by assigning a lambda expression to f, and 
then funcalling f of x:

(let (x) (setq x 1) (setq f (lambda (y) (+ y y))) (funcall f x)) => 2

or avoid the setqs as well since you're using let anyway:

(let (( x 1)
      (f (lambda (y) (+ y y))))
  (funcall f x))

=> 2
From: Raffael Cavallaro
Subject: Re: Memory-lapse CL question about eval and let
Date: 
Message-ID: <2006040418251375249-raffaelcavallaro@pasdespamsilvousplaitmaccom>
On 2006-04-04 18:20:03 -0400, Raffael Cavallaro 
<················@pas-d'espam-s'il-vous-plait-mac.com> said:

> On 2006-04-04 15:30:16 -0400, "Jon" <···@nospam.com> said:
> 
>> Thanks for realising what I meant and explaining the eval scope issue - I do
>> wonder how would you write it then (less messily than the extra let, if
>> that's possible)?
> 
> You could avoid using eval by assigning a lambda expression to f, and 
> then funcalling f of x:
> 
> (let (x) (setq x 1) (setq f (lambda (y) (+ y y))) (funcall f x)) => 2
> 
> or avoid the setqs as well since you're using let anyway:
> 
> (let (( x 1)
>       (f (lambda (y) (+ y y))))
>   (funcall f x))
> 
> => 2

... or even:

(funcall (lambda (x) (+ x x)) 1)

=> 2

or:

 (let ((x 1))
     (funcall (lambda (x) (+ x x)) x))

=> 2

It's not really clear what you're actually trying to do here though.
From: Jon
Subject: Re: Memory-lapse CL question about eval and let
Date: 
Message-ID: <12370kpe5cset34@corp.supernews.com>
It was a really shrunk down example of a much bigger thing. (With typos as
yesterday was manic, I think I have 20 separate things in motion this week.)

Basically I was allowing a user access to a function with a variable number
of arguments.

What I have is the function name, all the arguments and a list (collected
from the user) with the optional arguments (might be nil).

Yes, I know I could put the optional arguments into a list and have that as
one optional argument. Back when I was into Lisp I wasn't into CL, as I
thought it made Lisp ugly, so now I'm back I'm on a learning curve, as the
only decent Lisps these days seem to be the CL-alikes (Lispworks, Corman -
very 1980s environments though). Anyway, I just did what I'd do in the good
old days - make a list with the function name and parameters I know, bolt
the optional ones on the end and eval it. Then I got confused. I suspect
there are good reasons for the silly scope rules of eval, but it's
counter-intuitive to have things mid-function operate in a different scope,
so I'm not going to be impressed anytime soon. (I'm a big fan of getting a
good clear programming language and building on it, rather than having
articles like "Tricks and techniques that even {XXX} experts don't know
about" (I first saw these when {XXX} = C++, but it could be applied quite
widely.)

Anyway, plea for a nicer cleaner Lisp over (I've almost liked Scheme on
various occasions, but keep coming back to Lisp). All I was looking for was
a simple clean way to add the optional parameters and execute the function.

Thanks for everyone who replied, it is appreciated.

Jon
================
I don't do signatures, but just this once...
Programming languages used to date, if I remember correctly:
Fortran 4 (and 77 a bit)
C
Lisp
Prolog (which I always found a bit broken, due to back-tracking issues)
Assorted prototype functional programming languages (hope, others - gee it's
been a while, I did quite like hope though)
Snobol
APL (over a noisy dial-up line at first! luckily it mostly inserted $ signs
- I still can't believe Xerox used APL for accounts stuff though, very brave
- allows very big mistakes on a typo)
Many assemblers (inc PDP11, x86, about a dozen Microcontrollers), some in
binary through switches
BCPL
Basic
Java
{Gee, if I counted macro, markup and semi-languages, like PCL/PS, this would
go on for ever}

Which isn't bad for a hardware engineer... (though I learnt nearly half of
these at University, so hardware-ish)
P.S. what's with all you software guys, ask a 1960s AI programmer what a
current-spec personal computer would be like to interact with (4GHz CPU, 4GB
DRAM, x00s of GB of disk, etc.) and (s)he'd say it would be
indistinguishable from a person. Guys?!? (and Gals)
(The closest I've come is a very souped-up/expanded Eliza I wrote in the
1980s, on a BBC Micro (2MHz 6502) in Lisp. In addition to the slight
increase in CPU speed you have the internet too, I'd never seen the code of
the original when I wrote mine, I just knew the general theory from a
question on pattern-matching I'd had in some Lisp course-work from Uni.)
;-)
From: Jon
Subject: Re: Memory-lapse CL question about eval and let
Date: 
Message-ID: <12371rp9vu8dge6@corp.supernews.com>
P.S. I forgot Miranda, I'm deeply ashamed...
From: Pascal Bourguignon
Subject: Re: Memory-lapse CL question about eval and let
Date: 
Message-ID: <87sloschqp.fsf@thalassa.informatimago.com>
"Jon" <···@nospam.com> writes:
> Basically I was allowing a user access to a function with a variable number
> of arguments.
>
> What I have is the function name, all the arguments and a list (collected
> from the user) with the optional arguments (might be nil).

Variable number of arguments ==> &rest

(defun f (&rest args)
   (format t "--> ~{~A ~}~%" args))

(progn
   (f)
   (f 1)
   (f 1 2)
   (f 1 2 3)
   (dolist (args '(() (1) (1 2) (1 2 3) (1 2 3 4)))
      (apply (function f) args)))
Prints:
--> 
--> 1 
--> 1 2 
--> 1 2 3 
--> 
--> 1 
--> 1 2 
--> 1 2 3 
--> 1 2 3 4 


> Yes, I know I could put the optional arguments into a list and have that as
> one optional argument. Back when I was into Lisp I wasn't into CL, as I
> thought it made Lisp ugly, so now I'm back I'm on a learning curve, as the
> only decent Lisps these days seem to be the CL-alikes (Lispworks, Corman -
> very 1980s environments though). 

    http://www.cliki.net/Practical%20Lisp%20Programming


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

Nobody can fix the economy.  Nobody can be trusted with their finger
on the button.  Nobody's perfect.  VOTE FOR NOBODY.
From: Jon
Subject: Re: Memory-lapse CL question about eval and let
Date: 
Message-ID: <1237gv2oa7v2n85@corp.supernews.com>
You misunderstand, I'm not that much of a newbie to Lisp, just to CL. I
understand and am using &optional and &rest. I then wanted to add a layer on
top where the user specifies the arguments. After this I had the &rest part
in a list and simply needed to call the function, so I just glued the
optional bits onto the end of the fixed arguments and did an eval (this was
supposed to be a 5 minute hack to get someone something), only to be bitten
by the scope issue. (Many thanks for the explaination on that, BTW.)

The solution was trivial, I just used apply.

Jon
From: Pascal Bourguignon
Subject: Re: Memory-lapse CL question about eval and let
Date: 
Message-ID: <87fykscfee.fsf@thalassa.informatimago.com>
"Jon" <···@nospam.com> writes:

> You misunderstand, I'm not that much of a newbie to Lisp, just to CL. 

Oh, then you just need to read the CL standard:
http://www.lispworks.com/documentation/HyperSpec/Front/Contents.htm


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"By filing this bug report you have challenged the honor of my
family. Prepare to die!"
From: Jon
Subject: Re: Memory-lapse CL question about eval and let
Date: 
Message-ID: <1237n538b5aje8e@corp.supernews.com>
I had been reading the Hyperspec, but there's a lot of it, much of which I
know. What I really needed was the list of silly things that might catch
people out.... still that's one less on the list now.
From: Jon
Subject: Re: Memory-lapse CL question about eval and let
Date: 
Message-ID: <BYednbS7J--BVq_ZRVnygA@pipex.net>
Oops, scratch the let + (read) question - I had a non-printing character
buried in the original that was screwing it up, ho hum... feeling a bit
silly on that one.