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
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*)
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
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.