chicken-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Chicken-users] Binding identifiers with set!


From: felix
Subject: Re: [Chicken-users] Binding identifiers with set!
Date: Tue, 14 Oct 2003 01:53:31 +0200
User-agent: Opera7.11/Linux M2 build 406

On 14 Oct 2003 12:08:01 +1300, Bruce Hoult <address@hidden> wrote:


I think that would be immensely better than the current behaviour, but
not ideal.  Consider something like:

(let ((l '((a . 1) (b . 2) (c . 3) (d . 4))))
(define elt (caddr l))
(define key (car elt))
(define val (cdr elt))
(print "key=" key " val=" val))


=> key=c val=3


At the moment this works, albeit by polluting the global namespace.

Actually this expands into:

(let ((l0 '((a . 1) (b . 2) (c . 3) (d . 4))))
 (let ((elt1 (##core#undefined))
       (key2 (##core#undefined))
       (val3 (##core#undefined)))
   (let ((t4 (set! elt1 (caddr l0))))
     (let ((t5 (set! key2 (car elt1))))
       (let ((t6 (set! val3 (cdr elt1))))
         (print '"key=" key2 '" val=" val3))))))

So it does what you want and doesn't change the global environment.
Note that this is not strictly R5RS compliant, since the order
is unspecified (but because Chicken performs the assignments
sequentially, you get the desired (i.e. let*-ish) behaviour.


With your suggestion it won't work unless you insert some arbitrary
noise expression after the first define.

(let ((l '((a . 1) (b . 2) (c . 3) (d . 4))))
(define elt (caddr l))
#f
(define key (car elt))
(define val (cdr elt))
(print "key=" key " val=" val))

This seems messy, at best.

See above.



Perhaps what is needed is an entirely different binding form.  In some
of my own code I use a macro I call "begin/my", which can be used like
this:

(let ((l '((a . 1) (b . 2) (c . 3) (d . 4))))
(begin/my
(my elt (caddr l))
(my key (car elt))
(my val (cdr elt))
(print "key=" key " val=" val)))

The macro scans each form in its body to see if it starts with "my" and
if it does then it starts a new branch of a let*, otherwise it adds the
form to a "begin" on the previous branch of the let*.  e.g.


(let ((l '((a . 1) (b . 2) (c . 3) (d . 4))))
(begin/my
(foo)
(my elt (caddr l))
(bar)
(my key (car elt))
(baz)
(my val (cdr elt))
(print "key=" key " val=" val)))

=>

(let ((l '((a . 1) (b . 2) (c . 3) (d . 4))))
(let* ((elt (begin (foo) (caddr l)))
(key (begin (bar) (car elt)))
(val (begin (baz) (cdr elt))))
(print "key=" key " val=" val)))


Something similar that didn't need an explicit wrapper, but worked with
the built-in implicit bodies would be wonderful.  Even better if it
handled multiple-values:

(my (key val) (values (car elt) (cdr elt)))


Under the scheme I propose (letrec for all subsequent forms), you
would get the desired behaviour, too:

(define (foo) (print "foo"))

(let ((l '((a . 1) (b . 2) (c . 3) (d . 4))))
 (foo)
 (define elt (caddr l))
 (foo)
 (define key (car elt))
 (foo)
 (define-values (val noise) (values (cdr elt) 42))
 (print "key=" key " val=" val))

==>

(set! foo (lambda () (print '"foo")))
(let ((l0 '((a . 1) (b . 2) (c . 3) (d . 4))))
 (let ((t15 (foo)))
   (let ((elt1 (##core#undefined)))
     (let ((t13 (set! elt1 (caddr l0))))
       (let ((t14 (foo)))
         (let ((key2 (##core#undefined)))
           (let ((t11 (set! key2 (car elt1))))
             (let ((t12 (foo)))
               (let ((val5 (##core#undefined))
                     (noise6 (##core#undefined)))
                 (let ((t10 (##sys#call-with-values
                              (lambda () (values (cdr elt1) '42))
                              (lambda (val37 noise48)
                                (let ((t9 (set! val5 val37)))
                                  (set! noise6 noise48))))))
                   (print '"key=" key2 '" val=" val5)))))))))))


I have a theory that what turns many C/Java/Perl programmers off Lispy
languages is not in fact all the parens, but the way that every little
thing you do increases the indentation level, and many functions slope
off continuously to the right of the screen without ever unindenting. There are several very useful constructs that help to prevent this (e.g.
cond and let* and even when/unless) but there is no really good solution
for nests of "let".

Good point.


As you (Felix) know, I'm in the process of introducing embedded Scheme
scripting into the middle of my company's core product, and I'd like to
make things as easy and natural as possible for the other 60 programmers
who are going to have to work with this stuff instead of their usual
C++.






reply via email to

[Prev in Thread] Current Thread [Next in Thread]