From: Bryan King Parker
Subject: Lisp scope problems driving me NUTS!
Date: 
Message-ID: <4886jm$uu2@plucky.cs.utexas.edu>
OK, this is a complete newbie tip-off, but I would like to figure out
how to get Common Lisp to act more like... PASCAL!  :)  Sorry, flame
away if you feel the need.  Anyway, here's the scoop: I want to pass
a variable to a function which will be CHANGED.  I wouldn't mind using
a global variable (defvar), but the symbol the value will be bound to
is generated with (gensym), and I cannot get that to work with (defvar)
for some reason...?  Ie:

(defvar (gensym) (whatever))

Returns an error -- gensym is not a symbol.  However,

>(symbolp (gensym))
T

At any rate, the obvious correlation to Pascal programming is to pass
a VAR parameter to the function, but how to simulate this in Lisp is
beyond me... here is the bit of code I'm working with:

;; My program

(defun make-account ()
  (let* ((balance 0)
	 (balance-func
	  #'(lambda ()
	      balance))
	 (deposit-func
	  #'(lambda (amount)
	      (setq balance (+ balance amount))))
	 (withdraw-func
	  #'(lambda (amount)
	      (setq balance (- balance amount)))))
    #'(lambda (switch)
	(cond ((eq switch 'balance) balance-func)
	      ((eq switch 'deposit) deposit-func)
	      ((eq switch 'withdraw) withdraw-func)))))

(defun balance (account)
  (funcall (funcall account 'balance)))

(defun deposit (account amount)
  (funcall (funcall account 'deposit) amount))

(defun withdraw (account amount)
  (funcall (funcall account 'withdraw) amount))

(defun new-account ()
  (print "Enter account name: ")
  (let ((temp (read))
	(accountnum (gensym)))
    (setq *alist* (append *alist* (list (list temp accountnum))))
    (setf accountnum (make-account))
    (print "Enter initial balance: ")
    (setq amount (read))
    (funcall (funcall accountnum 'deposit) amount)))

;; End of LISP listing

Anyway, I obviously want to have the symbol generated by (gensym) to
hold on to its binding, since that is what encapsulates the object
functions... but HOW do I do this?  I can't pass it in, and I can't
declare the symbol globally... I guess I could encapsulate it somehow
like the bank account objects themselves, but this seems to be overkill
and I'm not real sure how to do it anyway. :/ 

Much obliged for any assistance.

	Bryan

From: David Neves
Subject: Re: Lisp scope problems driving me NUTS!
Date: 
Message-ID: <neves-1311951544590001@neves.ils.nwu.edu>
In article <··········@plucky.cs.utexas.edu>, ······@cs.utexas.edu (Bryan King Parker) wrote:

If you want to associate a name (of an account) with an (account) object then use hash tables -- just like you would do in any other language.  You don't really want to use symbols for this (although you could probably get away with using the SET function.  If a novice uses SET or EVAL they are probably doing something wrong.)
-David
From: Bruce R Miller
Subject: Re: Lisp scope problems driving me NUTS!
Date: 
Message-ID: <48be4o$8qj@ss1.cam.nist.gov>
In article <··········@plucky.cs.utexas.edu>,
	······@cs.utexas.edu (Bryan King Parker) writes:

You were doing fine till here.

>(defun new-account ()
>  (print "Enter account name: ")
>  (let ((temp (read))
>	(accountnum (gensym)))
>    (setq *alist* (append *alist* (list (list temp accountnum))))
>    (setf accountnum (make-account))
>    (print "Enter initial balance: ")
>    (setq amount (read))
>    (funcall (funcall accountnum 'deposit) amount)))

I'm not sure I quite understand your comments; you dont need to assign the
account to anything for it to maintain its state: accountnum is a local 
variable, in any case.   But, I think what you want is more like
this:   (with a few gratuitous stylistic mods, hint! :> )

(defun prompt-and-read (prompt)
   (print prompt)
   (read))

(defun new-account ()
  (let ((name (prompt-and-read "Enter account name: "))
        (init (prompt-and-read "Enter initial balance: "))
	(account (make-account)))
    (deposit account init)
    (setq *alist* (append *alist* (list (list name account)))))
    account)

You dont need to assign the account to any particular symbol, gensym'd or 
otherwise;  it's already stored in the (presumably global) *alist*.
(And I assume there'll be an accessor to lookup accounts by name?)
The object itself maintains its state.  The only reason you need to assign
it to something is to have a handle on it to use it later.
Eg. either
  (setq myaccount (new-account))
or
  (assoc UT-FCU *alist*)
From: Len Charest
Subject: Re: Lisp scope problems driving me NUTS!
Date: 
Message-ID: <48bfpa$rlk@cyclops.dsphere.net>
I haven't posted on comp.lang.lisp in ages, but this question is relatively
easy and I'm tired of staring at perl scripts, so here goes.

>(defvar (gensym) (whatever))
>
>Returns an error -- gensym is not a symbol.  However,
>
>>(symbolp (gensym))
>T

DEFVAR requires that it's first argument be a literal symbol.

>Anyway, I obviously want to have the symbol generated by (gensym) to
>hold on to its binding, since that is what encapsulates the object
>functions... but HOW do I do this?

Another poster has already suggested that hashing is a better solution to your
mapping problem, but if you insist on using GENSYM, look very carefully at this
example.

(defvar test (gensym))		; test is bound to a new (uninterned) symbol
(boundp 'test)			; will return T
(boundp test)			; will return NIL since TEST evaluates to the
				; new symbol, which is *not* bound to anything
				; (i.e., the gensym does not have a value)
(set test 123)			; binds the *value* of test to 123; i.e., binds
				; the gensym to 123
(boundp test)			; will return T
(print test)			; will print the name of the gensym
(print (symbol-value test))	; will print the value of the gensym
From: Eliot Handelman
Subject: Re: Lisp scope problems driving me NUTS!
Date: 
Message-ID: <elito-1511950333460001@a-10.das.mcgill.ca>
In article <··········@plucky.cs.utexas.edu>, ······@cs.utexas.edu (Bryan
King Parker) wrote:

> OK, this is a complete newbie tip-off, but I would like to figure out
> how to get Common Lisp to act more like... PASCAL!  :)  

Isn't that what PROG is for?

>I want to pass
> a variable to a function which will be CHANGED.  I wouldn't mind using
> a global variable (defvar), but the symbol the value will be bound to
> is generated with (gensym), and I cannot get that to work with (defvar)
> for some reason...?  Ie:
> 
> (defvar (gensym) (whatever))
> 
> Returns an error -- gensym is not a symbol.  However,

> >(symbolp (gensym))
> T

Naturally. DEFVAR doesn't evaluate the first argument. 

Here's one solution:

(defvar *generated-account-number* (gentemp "ACCOUNT-"))

You could get the value like this:

(symbol-value *generated-account-number*)

and set it like this:

(setf (symbol-value *generated-account-number*) 0)


>(defun new-account ()
>  (print "Enter account name: ")
>  (let ((temp (read))
>        (accountnum (gensym)))
>    (setq *alist* (append *alist* (list (list temp accountnum))))
>    (setf accountnum (make-account))
>    (print "Enter initial balance: ")
>    (setq amount (read))
>    (funcall (funcall accountnum 'deposit) amount)))


So you would write:

(define new-account ()
   (let ((acount-name nil)
         (initial-amount 0))
     (format t "Enter account name: ")
     (setq account-name (read))
     (format t "Enter initial balance: ")
     (setq initial-balance (read))
     (setq *generated-account-number* (gentemp "ACCOUNT-"))
     (setf (symbol-value *generated-account-number*)
            (make-account))
     (funcall (funcall (symbol-value *generated-account-number*)
                        'deposit)
               initial-amount)))


In your position, incidentally, I wouldn't fear flames -- I'd embrace
them. You might learn something.