Discussion:
[racket] Why choose the 'let*' construct over the 'define' construct when both can have sequential scope?
Don Green
2015-02-19 17:40:45 UTC
Permalink
What is/are the reason(s) for choosing the 'let*' construct over the
'define' construct?

(define (print-two f)
(let* ([_ (print (first f))]
[f (rest f)]
[_ (print (first f))]
[f (rest f)])
f))

(define print-two
(lambda (f)
(print (first f))
(set! f (rest f))
(print (first f))
(set! f (rest f))
f))

(void (print-two '(1 2))) ;=> 12
Matthias Felleisen
2015-02-19 17:49:16 UTC
Permalink
In some places, you are allowed only one expression, and for that situation, you need let*.
What is/are the reason(s) for choosing the 'let*' construct over the 'define' construct?
(define (print-two f)
(let* ([_ (print (first f))]
[f (rest f)]
[_ (print (first f))]
[f (rest f)])
f))
(define print-two
(lambda (f)
(print (first f))
(set! f (rest f))
(print (first f))
(set! f (rest f))
f))
(void (print-two '(1 2))) ;=> 12
____________________
http://lists.racket-lang.org/users
____________________
Racket Users list:
http://lists.racket-lang.org/users
Laurent
2015-02-19 18:24:28 UTC
Permalink
But in such situations you can be vicious and abuse `let` to have your
`define`s:
(let ()
(define x 3)
(define y 4)
(list x y))

It's even more vicious if you use `let*` instead of `let`, but quite less
if you use `begin` instead ;)
Post by Matthias Felleisen
In some places, you are allowed only one expression, and for that situation, you need let*.
Post by Don Green
What is/are the reason(s) for choosing the 'let*' construct over the
'define' construct?
Post by Don Green
(define (print-two f)
(let* ([_ (print (first f))]
[f (rest f)]
[_ (print (first f))]
[f (rest f)])
f))
(define print-two
(lambda (f)
(print (first f))
(set! f (rest f))
(print (first f))
(set! f (rest f))
f))
(void (print-two '(1 2))) ;=> 12
____________________
http://lists.racket-lang.org/users
____________________
http://lists.racket-lang.org/users
Jens Axel Søgaard
2015-02-19 18:32:08 UTC
Permalink
We have let and let*, but only define. I miss define* at times.

This is an error:

(block
(define x 4)
(define x (+ x 1))
(+ x 2))

With a define* it becomes:

(block
(define x 4)
(define* x (+ x 1))
(+ x 2))

which (should) expand to:

(block
(define x 4)
(block
(define x (+ x 1))
(+ x 2)))

/Jens Axel
Post by Laurent
But in such situations you can be vicious and abuse `let` to have your
(let ()
(define x 3)
(define y 4)
(list x y))
It's even more vicious if you use `let*` instead of `let`, but quite less if
you use `begin` instead ;)
Post by Matthias Felleisen
In some places, you are allowed only one expression, and for that
situation, you need let*.
Post by Don Green
What is/are the reason(s) for choosing the 'let*' construct over the
'define' construct?
(define (print-two f)
(let* ([_ (print (first f))]
[f (rest f)]
[_ (print (first f))]
[f (rest f)])
f))
(define print-two
(lambda (f)
(print (first f))
(set! f (rest f))
(print (first f))
(set! f (rest f))
f))
(void (print-two '(1 2))) ;=> 12
____________________
http://lists.racket-lang.org/users
____________________
http://lists.racket-lang.org/users
____________________
http://lists.racket-lang.org/users
--
--
Jens Axel Søgaard

____________________
Racket Users list:
Matthias Felleisen
2015-02-19 18:37:52 UTC
Permalink
I recommend a macro for these situations, it's almost always what you want:

(thread-through x e_0 e ...)
==
(let ([x e_0])
(set! x e)
...
x)

(you can also use let* here).

This brings across what you're really doing.
Post by Jens Axel Søgaard
We have let and let*, but only define. I miss define* at times.
(block
(define x 4)
(define x (+ x 1))
(+ x 2))
(block
(define x 4)
(define* x (+ x 1))
(+ x 2))
(block
(define x 4)
(block
(define x (+ x 1))
(+ x 2)))
/Jens Axel
Post by Laurent
But in such situations you can be vicious and abuse `let` to have your
(let ()
(define x 3)
(define y 4)
(list x y))
It's even more vicious if you use `let*` instead of `let`, but quite less if
you use `begin` instead ;)
Post by Matthias Felleisen
In some places, you are allowed only one expression, and for that
situation, you need let*.
Post by Don Green
What is/are the reason(s) for choosing the 'let*' construct over the
'define' construct?
(define (print-two f)
(let* ([_ (print (first f))]
[f (rest f)]
[_ (print (first f))]
[f (rest f)])
f))
(define print-two
(lambda (f)
(print (first f))
(set! f (rest f))
(print (first f))
(set! f (rest f))
f))
(void (print-two '(1 2))) ;=> 12
____________________
http://lists.racket-lang.org/users
____________________
http://lists.racket-lang.org/users
____________________
http://lists.racket-lang.org/users
--
--
Jens Axel Søgaard
____________________
Racket Users list:
http://lists.racket-lang.org/users
Alexander D. Knauth
2015-02-19 20:07:22 UTC
Permalink
Because of this: http://docs.racket-lang.org/guide/set_.html#%28part._using-set%21%29
Would this be better:
(thread-through x e …)
==
(let* ([x e] …) x)
Post by Matthias Felleisen
(thread-through x e_0 e ...)
==
(let ([x e_0])
(set! x e)
...
x)
(you can also use let* here).
This brings across what you're really doing.
Post by Jens Axel Søgaard
We have let and let*, but only define. I miss define* at times.
(block
(define x 4)
(define x (+ x 1))
(+ x 2))
(block
(define x 4)
(define* x (+ x 1))
(+ x 2))
(block
(define x 4)
(block
(define x (+ x 1))
(+ x 2)))
/Jens Axel
Post by Laurent
But in such situations you can be vicious and abuse `let` to have your
(let ()
(define x 3)
(define y 4)
(list x y))
It's even more vicious if you use `let*` instead of `let`, but quite less if
you use `begin` instead ;)
Post by Matthias Felleisen
In some places, you are allowed only one expression, and for that
situation, you need let*.
Post by Don Green
What is/are the reason(s) for choosing the 'let*' construct over the
'define' construct?
(define (print-two f)
(let* ([_ (print (first f))]
[f (rest f)]
[_ (print (first f))]
[f (rest f)])
f))
(define print-two
(lambda (f)
(print (first f))
(set! f (rest f))
(print (first f))
(set! f (rest f))
f))
(void (print-two '(1 2))) ;=> 12
____________________
http://lists.racket-lang.org/users
____________________
http://lists.racket-lang.org/users
____________________
http://lists.racket-lang.org/users
--
--
Jens Axel Søgaard
____________________
http://lists.racket-lang.org/users
____________________
Racket Users list:
http://lists.racket-lang.org/users
Eric Dong
2015-02-20 13:44:24 UTC
Permalink
Yes, expanding to let* will indeed be better for the optimizer. The
optimizer, IIRC, currently uses a "You using set!? I give up" approach, and
if you ever mention set!-ing the variable, the compiler will then insert
typechecks every time the variable is used, slowing down things, and also
box anything stored in it. While if a variable is not assigned to, usages
of it do not need to check its type over and over. At least that's what I
understood.
Post by Alexander D. Knauth
http://docs.racket-lang.org/guide/set_.html#%28part._using-set%21%29
(thread-through x e 
)
==
(let* ([x e] 
) x)
Post by Matthias Felleisen
I recommend a macro for these situations, it's almost always what you
(thread-through x e_0 e ...)
==
(let ([x e_0])
(set! x e)
...
x)
(you can also use let* here).
This brings across what you're really doing.
Post by Jens Axel Søgaard
We have let and let*, but only define. I miss define* at times.
(block
(define x 4)
(define x (+ x 1))
(+ x 2))
(block
(define x 4)
(define* x (+ x 1))
(+ x 2))
(block
(define x 4)
(block
(define x (+ x 1))
(+ x 2)))
/Jens Axel
Post by Laurent
But in such situations you can be vicious and abuse `let` to have your
(let ()
(define x 3)
(define y 4)
(list x y))
It's even more vicious if you use `let*` instead of `let`, but quite
less if
Post by Matthias Felleisen
Post by Jens Axel Søgaard
Post by Laurent
you use `begin` instead ;)
On Thu, Feb 19, 2015 at 5:49 PM, Matthias Felleisen <
Post by Matthias Felleisen
In some places, you are allowed only one expression, and for that
situation, you need let*.
Post by Don Green
What is/are the reason(s) for choosing the 'let*' construct over the
'define' construct?
(define (print-two f)
(let* ([_ (print (first f))]
[f (rest f)]
[_ (print (first f))]
[f (rest f)])
f))
(define print-two
(lambda (f)
(print (first f))
(set! f (rest f))
(print (first f))
(set! f (rest f))
f))
(void (print-two '(1 2))) ;=> 12
____________________
http://lists.racket-lang.org/users
____________________
http://lists.racket-lang.org/users
____________________
http://lists.racket-lang.org/users
--
--
Jens Axel SÞgaard
____________________
http://lists.racket-lang.org/users
____________________
http://lists.racket-lang.org/users
Loading...