[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: questioning let
From: |
Andreas Röhler |
Subject: |
Re: questioning let |
Date: |
Wed, 24 Feb 2010 18:44:53 +0100 |
User-agent: |
Thunderbird 2.0.0.19 (X11/20081227) |
Pascal J. Bourguignon wrote:
> Andreas Roehler <andreas.roehler@online.de> writes:
>
>> Hi,
>>
>> behaviour of the example code below puzzles me. Would
>> expect setting of arg by external function, but inside
>> `let', recognised. But remains `1'.
>>
>> (defun arg-setting ()
>> (interactive)
>> (let ((arg 1))
>> (message "%s" arg)
>> (arg-extern arg)
>> (message "%s" arg)))
>>
>> (defun arg-extern (arg)
>> (setq arg (1- arg)))
>>
>> Any help?
>
>
> let is equivalent to lambda:
>
> (let ((a 1) (b 2)) (list a b)) <=> ((lambda (a b) (list a b)) 1 2)
>
> defun is binding a lambda to a function cell:
>
> (defun f (a b) (list a b))
> <=> (setf (symbol-function 'f) (lambda (a b) (list a b)))
>
> Therefore you can see that calling a function defined by defun is a let
> in disguise.
>
>
> If you transformed your code following these equivalences, you would
> notice that you have actually TWO variables named arg, one as parameter
> of the function arg-extern, and one as variable in the let in
> arg-setting.
>
> The setq in arg-extern will modify only the variable parameter of
> arg-extern. Because they have the same name, this variable hides the
> one defined in the let of arg-setting. There's no way to access it from
> within arg-extern.
>
>
> If they had a different name, you could modify a variable from an outer
> dynamic scope from an inner dynamic scope, because in emacs all the
> variables are dynamic. But it is considered very bad form to do so:
> this is a big side effect, and what's more, one that depends on the call
> chain. You should avoid side effects, to increase the readability and
> debugability of your code. Therefore you should avoid setq and setf.
> Try to write pure function, never try to modify a variable.
>
> One way to write your code would be:
>
> (defun do-what-you-need-to-do-with (arg)
> )
>
> (defun arg-binding ()
> (interactive)
> (let ((arg 1))
> (message "before arg = %s" arg)
> (let ((arg (arg-extern arg)))
> (message "after arg = %s" arg)
> (do-what-you-need-to-do-with arg))
> (message "original arg = %s" arg)))
>
> (defun arg-extern (arg)
> (message "arg-extern before arg = %s" arg)
> (message "arg-extern returns = %s" (1- arg))
> (1- arg))
>
> before arg = 1
> arg-extern before arg = 1
> arg-extern returns = 0
> after arg = 0
> original arg = 1
>
>
> If you need a global variable (perhaps because you need to keep some
> data across command invocations), the I would advise to distringuish it
> from the other by giving it a name surrounded by stars: *var*. Then, it
> will have a different name, and won't be shadowed (inadvertantly) by
> inner lets, defuns or lambdas.
>
> (defvar *var* 42)
>
> (defun arg-extern (arg)
> (message "arg-extern before arg = %s" arg)
> (setf *var* (1- arg))
> (message "arg-extern returns = %s" *var*)
> *var*)
>
> (arg-binding)
> *var* --> 0
>
>
Hi Pascal,
thanks a lot for these helpful instructions.
Next days it should go here:
http://repo.or.cz/w/elbb.git
Andreas
BTW every Emacs hacker is invited recording it's stuff there
It's about playing with git too...
Re: questioning let, Pascal J. Bourguignon, 2010/02/24
- Re: questioning let,
Andreas Röhler <=
Re: questioning let, Tim X, 2010/02/24