Reputation: 673
What is the difference between two functions in Scheme, one defined like this—
(define doSomething
(lambda (x)
(let (f (100))
(f x))))
and the other like this?—
(define doSomething
(let (f (100))
(lambda (x)
(f x))))
In other words, what does it matter if the lambda
is before the let
or after it?
Upvotes: 3
Views: 1566
Reputation: 8485
As Chris points out, the code isn't going to run. So I'm going to use a new example to explain the let
over lambda
idiom.
When you surround a lambda
form with a let
like this:
(let ((x 0))
(lambda ()
; body
))
The code inside the body of the lambda
is able to access (including modify) x
, even after the let
ends and returns the new function. This is one example of creating a "closure" which is tricky to understand at first.
Essentially this means that you can create a function with a kind of "internal state". You can use this to do things like make "accumulator generators" or make functions that count the number of times they've been called, or even simulate "objects" (internal state + methods). Here's some contrived examples:
A double
function that counts the number of times it's been called:
(define double
(let ((count 0)) ; closed over variable
(lambda (x)
(if (eq? x 'count)
count
(begin
(set! count (+ count 1)) ; incr the count variable introduced by let
(+ x x))))))
> (double 1)
2
> (double 1)
2
> (double 1)
2
> (double 'count) ; ask the double function how many times it's been called
3
>
This example is really courtesy Paul Graham (http://www.paulgraham.com/accgen.html)
(define make-accumulator
(lambda ()
(let ((x 0))
(lambda (i)
(set! x (+ x i)) ; incr x by i
x))))
> (define acc (make-accumulator))
> (acc 1)
1
> (acc 1)
2
> (acc 1)
3
> (acc 1)
4
>
Each time acc
is called with 1
the value it returns is different.
For examples of "objects" search for "objects and closures" or just read the relevant sections of SICP: http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-20.html#%_sec_3.1
Upvotes: 5
Reputation: 17203
One point that the other two (excellent) posters circle around but don't explicitly mention is this: in the absence of set!
, there's no difference between the two, and therefore probably no reason to use your second form.
Upvotes: 2
Reputation: 222973
Your code won't run. :-)
I will presume that you mean these instead:
(lambda (x)
(let ((f 100))
(+ f x)))
and
(let ((f 100))
(lambda (x)
(+ f x)))
In both cases, you'll get back the passed-in argument plus 100.
However, the main difference (ignoring technicalities about how let
is just syntactic sugar over lambda
) is that in the second version, f
is a free variable. Say we do this:
(let ((f 100))
(list (lambda (x)
(+ f x))
(lambda (x)
(set! f x))))
This returns a list with two lambdas: the first of which is just like the ones previously, and the second one which allows you to change the value of f
. Both lambdas access the same f
, so running the setter will affect later calls to the first lambda.
Upvotes: 5