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: Bruce Hoult
Subject: Re: [Chicken-users] Binding identifiers with set!
Date: 14 Oct 2003 12:08:01 +1300

On Tue, 2003-10-14 at 11:18, felix wrote:
> Well, you could handle this by treating every sequence of local defintions
> as a letrec. So for example
> 
> (let (...)
>   (define foo 1)
>   (define bar 2)
>   (print "oink!")
>   (define baz 3)
>   (define quux 4)
>   ...)
> 
> would expand into:
> 
> (let (...)
>   (letrec ([foo 1] [bar 2])
>     (print "oink!")
>     (letrec ([baz 3] [quux 4])
>       ...) ) )
> 
> This would be compliant to R5RS (for the first set of definitions).
> 
> Would this be useful?

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.

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.


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


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".

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++.

-- 
Bruce Hoult <address@hidden>





reply via email to

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