Ok, this is a fairly basic question: I am following the SICP videos, and I am a bit confused about the differences between define
, let
and set!
.
1) According to Sussman in the video, define
is allowed to attach a value to avariable only once (except when in the REPL), in particular two defines in line are not allowed. Yet Guile happily runs this code
(define a 1) (define a 2) (write a)
and outputs 2, as expected. Things are a little bit more complicated because if I try to do this (EDIT: after the above definitions)
(define a (1+ a))
I get an error, while
(set! a (1+ a))
is allowed. Still I don't think that this the only difference between set!
and define
: what is that I am missing?
2) The difference between define
and let
puzzles me even more. I know in theory let
is used to bind variables in local scope. Still, it seems to me that this works the same with define
, for instance I can replace
(define (f x) (let ((a 1)) (+ a x)))
with
(define (g x) (define a 1) (+ a x))
and f
and g
work the same: in particular the variable a
is unbound outside g
as well.
The only way I can see this useful is that let
may have a shorter scope that the whole function definition. Still it seems to me that one can always add an anonymous function to create the necessary scope, and invoke it right away, much like one does in javascript. So, what is the real advantage of let
?
Your confusion is reasonable: 'let' and 'define' both create new bindings. One advantage to 'let' is that its meaning is extraordinarily well-defined; there's absolutely no disagreement between various Scheme systems (incl. Racket) about what plain-old 'let' means.
The 'define' form is a different kettle of fish. Unlike 'let', it doesn't surround the body (region where the binding is valid) with parentheses. Also, it can mean different things at the top level and internally. Different Scheme systems have dramatically different meanings for 'define'. In fact, Racket has recently changed the meaning of 'define' by adding new contexts in which it can occur.
On the other hand, people like 'define'; it has less indentation, and it usually has a "do-what-I-mean" level of scoping allowing natural definitions of recursive and mutually recursive procedures. In fact, I got bitten by this just the other day :).
Finally, 'set!'; like 'let', 'set!' is pretty straightforward: it mutates an existing binding.
FWIW, one way to understand these scopes in DrRacket (if you're using it) is to use the "Check Syntax" button, and then hover over various identifiers to see where they're bound.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With